Read and write JSON documents in Java with Jackson
I’m working on my graph tool and I just changed the file format to JSON, then the need to read and write JSON from and to a file.
What I needed was a lightweight library to parse and export JSON content, nothing fancy … wait, with support for pretty printing, please. I ended up with Jackson, not exactly lightweight, but it did the job.
There are many libraries for this task, json-simple, Google Gson, Jackson, to name a few. My first try was with json-simple, it’s okay, but it lacks of pretty printing. I din’t spend too much time on Gson, but it seems that is more suited to map JSON data to classes (and conversely). Jackson was tedious to set up because I had to guess what jar file to use, jackson-core, maybe jackson-databind, jackson-annotations, or all of them! I stayed with Jackson because the Tree Model seemed very convenient to read, and indeed it is.
Enough chitchat. Here is the input file that we’ll parse:
{
"Graph": {
"Edges": [
{
"center": {
"x": -6.516290726817042,
"y": 1.8379281537176269
},
"end": 2,
"label": "10",
"labelColor": "0x000000ff",
"start": 1,
"strokeColor": "0x000000ff",
"strokeSize": 1.0
},
{
"center": {
"x": 0.4594820384294058,
"y": 6.265664160401002
},
"end": 3,
"label": "5",
"labelColor": "0x000000ff",
"start": 1,
"strokeColor": "0x000000ff",
"strokeSize": 1.0
},
{
"center": {
"x": 1.0860484544695055,
"y": -1.4619883040935668
},
"end": 2,
"label": "7",
"labelColor": "0x000000ff",
"start": 3,
"strokeColor": "0x000000ff",
"strokeSize": 1.0
}
],
"Vertices": [
{
"backgroundColor": "0x006699ff",
"borderColor": "0xffffff00",
"center": {
"x": -7.142857142857142,
"y": 9.064327485380117
},
"key": 1,
"label": "A",
"labelColor": "0xffffffff",
"radius": 1.42879125952273
},
{
"backgroundColor": "0x006699ff",
"borderColor": "0xffffff00",
"center": {
"x": -5.889724310776942,
"y": -6.390977443609022
},
"key": 2,
"label": "B",
"labelColor": "0xffffffff",
"radius": 1.42879125952273
},
{
"backgroundColor": "0x006699ff",
"borderColor": "0xffffff00",
"center": {
"x": 8.061821219715952,
"y": 2.4644945697577283
},
"key": 3,
"label": "C",
"labelColor": "0xffffffff",
"radius": 1.4287912595227292
}
]
}
}
And here is the code I used to parse it:
import java.io.*;
import java.util.Iterator;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonEncoding;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.exc.InvalidFormatException;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
public class TestJsonRead {
public static void readJson() throws InvalidFormatException, IOException
{String fileName = "input.json"; // in the current working directory
File input = new File(fileName);
new ObjectMapper();
ObjectMapper mapper = readTree(input);
JsonNode root = mapper.Iterator<JsonNode> V = root.path("Graph").path("Vertices").elements();
while (V.hasNext()) {
System.out.println("=== Start vertex ===");
next();
JsonNode v = V.if (v.get("key") == null || v.get("label") == null) {
throw new InvalidFormatException(
"Vertex's key and label are not optional.",
null, null, null
);
}
Integer key = v.path("key").asInt();
String label = v.path("label").textValue();
if (v.get("center") != null) {
get("center");
JsonNode point = v.if (point.get("x") != null && point.get("y") != null) {
double x = point.get("x").asDouble();
double y = point.get("y").asDouble();
System.out.printf("Center = (%f, %f)\n", x, y);
}
}
if (v.get("radius") != null) {
Double radius = v.get("radius").asDouble();
System.out.println("Radius = " + radius);
}
if (v.get("labelColor") != null) {
String hex = v.get("labelColor").textValue();
System.out.println("Label color = " + hex);
}
if (v.get("backgroundColor") != null) {
String hex = v.get("backgroundColor").textValue();
System.out.println("Background color = " + hex);
}
if (v.get("borderColor") != null) {
String hex = v.get("borderColor").textValue();
System.out.println("Border color = " + hex);
}
System.out.println();
}
Iterator<JsonNode> E = root.get("Graph").get("Edges").elements();
while (E.hasNext()) {
next();
JsonNode e = E.System.out.println("=== Start edge ===");
if (e.get("start") == null || e.get("end") == null) {
throw new InvalidFormatException(
"start and end are not optional.",
null, null, null
);
}
Integer start = e.get("start").asInt();
Integer end = e.get("end").asInt();
System.out.println("start = " + start);
System.out.println("end = " + end);
if (e.get("label") != null) {
String label = e.get("label").textValue();
System.out.println("label = " + label);
}
if (e.get("labelColor") != null) {
String hex = e.get("labelColor").textValue();
System.out.println("label color = " + hex);
}
if (e.get("strokeColor") != null) {
String hex = e.get("strokeColor").textValue();
System.out.println("stroke color = " + hex);
}
if (e.get("strokeSize") != null) {
String str = e.get("strokeSize").toString();
System.out.println("stroke size = " + str);
}
if (e.get("center") != null) {
get("center");
JsonNode point = e.if (point.get("x") != null && point.get("y") != null) {
double x = point.get("x").asDouble();
double y = point.get("y").asDouble();
System.out.printf("center = (%f, %f)\n", x, y);
}
}System.out.println();
}
}
public static void main(String[] args)
{try {
readJson();
catch (InvalidFormatException ife) {
} System.out.println("Error: " + ife.getMessage());
catch (IOException ioe) {
} printStackTrace();
ioe.
}
} }
Compile and run with:
javac -cp .:jackson-annotations-2.4.0.jar:jackson-core-2.4.0.jar:jackson-databind-2.4.0.jar TestJsonRead.java
java -cp .:jackson-annotations-2.4.0.jar:jackson-core-2.4.0.jar:jackson-databind-2.4.0.jar TestJsonRead
Download the Jars from http://repo1.maven.org/maven2/com/fasterxml/jackson/core/ or use Google to find them.
Actually I don’t just read the data and print it out, but store it in some data structures. Here’s how the writing looks like:
private void saveToGi() throws JsonGenerationException, IOException
{Map<Integer, Vertex> graph = plane.getGraph();
new JsonFactory();
JsonFactory factory = File output = new File(fileName);
createGenerator(
JsonGenerator generator = factory.
output,UTF8
JsonEncoding.
);
// Basic Pretty print
setPrettyPrinter(new DefaultPrettyPrinter());
generator.
writeStartObject();
generator.writeFieldName("Graph");
generator.writeStartObject();
generator.writeFieldName("Vertices");
generator.writeStartArray();
generator.for (Entry<Integer, Vertex> entry : graph.entrySet()) {
getValue();
Vertex v = entry.String hexLabelColor = encode(v.getLabelColor());
String hexBorderColor = encode(v.getBorderColor());
String hexBackgroundColor = encode(v.getBackgroundColor());
writeStartObject();
generator.writeNumberField("key", v.getKey());
generator.writeStringField("label", v.getLabel());
generator.writeNumberField("radius", v.getRadius());
generator.writeStringField("labelColor", hexLabelColor);
generator.writeStringField("backgroundColor", hexBackgroundColor);
generator.writeStringField("borderColor", hexBorderColor);
generator.
writeFieldName("center");
generator.writeStartObject();
generator.writeNumberField("x", v.getCenter().x());
generator.writeNumberField("y", v.getCenter().y());
generator.writeEndObject();
generator.
writeEndObject();
generator.
}writeEndArray();
generator.
writeFieldName("Edges");
generator.writeStartArray();
generator.for (Entry<Integer, Vertex> vertexEntry : graph.entrySet()) {
getValue();
Vertex v = vertexEntry.for (Entry<Integer, Edge> edgeEntry: v.getNeighbors().entrySet()) {
writeStartObject();
generator.getValue();
Edge e = edgeEntry.String hexLabelColor = encode(e.getLabelColor());
String hexStrokeColor = encode(e.getStrokeColor());
writeNumberField("start", e.getStart());
generator.writeNumberField("end", e.getEnd());
generator.writeStringField("label", e.getLabel());
generator.writeStringField("labelColor", hexLabelColor);
generator.writeStringField("strokeColor", hexStrokeColor);
generator.writeNumberField("strokeSize", e.getStrokeSize());
generator.
writeFieldName("center");
generator.writeStartObject();
generator.writeNumberField("x", e.getLabelCenter().x());
generator.writeNumberField("y", e.getLabelCenter().y());
generator.writeEndObject();
generator.
writeEndObject();
generator.
}
}
close();
generator. }
This code doesn’t compile by itself because it depends on some classes that I use in my project, but it gives you the idea. You can find the full source code here.
I hope it helps. Bye!