JSON has been around for quite sometime now and lot of languages are offering out of the box support for parsing and creating JSON data. The JDK didn’t have support for parsing and creating JSON data out of the box. One had to make use of libraries for parsing and creating JSON data like Google GSON among others. With JSR 353 and its reference implementation we can hope that it becomes a part of JDK so that we are less dependent on 3rd party libraries. JavaEE 7 reference implementation that comes with Glassfish 4 already contains the reference implementation for JSR 353 and I have already covered few post which show how to parse JSON data in JavaEE 7.
In this post I will make use of the reference implementation of JSR 353 outside of the JavaEE 7 i.e outside of a server application deployed on Glassfish 4. Firstly you can get access to the reference implementation from here. As this JSR reference implementation is still not part of JDK we would have to download the external jars for this implementation and use it like the way we used 3rd party libraries i.e add them to your application’s or project’s classpath. You will have to download the following 2 jars and add them to your project’s class path before proceeding with the rest of the post:
- Jar for compiling an application with JSON Processing API.
- Jar for runing an application with JSON Processing API.
This post is divided into 2 parts namely:
- Creating JSON data using the JSON Streaming API.
- Creating JSON data using the JSON Object Model API.
But before that you should have the 2 jars mentioned above in you classpath.
JSON data to be created
In this post my aim is to show you all how to create the following JSON data using the JSON Streaming API and JSON Object Model API.
[ { "parentid": 23424900, "name": "Mexico City", "url": "http://where.yahooapis.com/v1/place/116545", "placeType": { "name": "Town", "code": 7 }, "woeid": 116545 }, { "name": "Jackson", "url": "http://where.yahooapis.com/v1/place/2428184", "placeType": { "name": "Town", "code": 7 }, "parentid": 23424977, "woeid": 2428184 } ]
Creating JSON Data Using The JSON Streaming API
We have already seen how to parse the JSON data using the JSON Streaming API. Lets now look at how to create the JSON data using the JSON Streaming API. The following classes from the API will be used for creating the data:
- JsonGenerator: Writes JSON data to an output source in a streaming way. The class Json contains methods to create generators for character or output streams (Writer and OutputStream).
- Json: Factory class for creating JSON processing objects. This class provides the most commonly used methods for creating these objects and their corresponding factories. The factory classes provide all the various ways to create these objects.
- StringWriter: A character stream that collects its output in a string buffer, which can then be used to construct a string.
One can write the JSON data to any character stream or a byte stream. In this sample I will be using a StringWriter to buffer up the JSON data and then generate the string representing the JSON data. The below method is used to create JSON data using the Streaming API. If you see the code below you can find out some kind of a pattern appearing while you invoke different methods to create the data, the pattern some what appears like an language. Yes, if you have guessed it as an DSL you are right. Its actually an Internal DSL and the technique is called Method Chaining. This is the term used by Martin Fowler in his DSL book.
private static void buildJsonUsingStreamingApi() { //Create a StringWriter instance to buffer the JSON data. StringWriter writer = new StringWriter(); //Create a JSON generator backed by the StringWriter instance created above. JsonGenerator generator = Json.createGenerator(writer); //Start building the JSON Data- Uses Method chaining technique. //The JSON data gets streamed in the buffer as and when the //different methods are invoked. generator.writeStartArray() .writeStartObject()//Indicates the start of an JSON object .write("parentid", 23424900) .write("name","Mexico City") .write("url", "http://where.yahooapis.com/v1/place/116545") .writeStartObject("placeType")//Creating a nested object i.e an JSON object withing another object .write("name","Town") .write("code", 7) .writeEnd() .write("woeid", 116545) .writeEnd()//Indicates the end of an JSON object .writeStartObject() .write("name","Jackson") .write("url", "http://where.yahooapis.com/v1/place/2428184") .writeStartObject("placeType") .write("name","Town") .write("code", 7) .writeEnd() .write("parentid", 23424977) .write("woeid", 2428184) .writeEnd() .writeEnd();//Indicates the end of the JSON array. //Writes the data in the buffer to the String buffer. generator.flush(); //Prints the JSON data onto the console. System.out.println(writer.toString()); }
In the above code you have seen the write()
being invoked with different data types namely: Integer, String. If we happen to look at the API supported by JsonGenerator, we can see that it supports the following data types namely: BigDecimal, BigInteger, boolean, double, int, long, String, null and any other JsonValue like JsonObject, JsonArray, JsonString, JsonNumber, JsonValue.TRUE, JsonValue.FASLE, JsonValue.NULL. And these are the data types supported by the JSR 353 JSON API.
The above code should produce the following output:
//Start of JSON Array. [ //Start of JSON Object {"parentid":23424900,"name":"Mexico City","url":"http://where.yahooapis.com/v1/place/116545","placeType": //Start of nested JSON Object {"name":"Town","code":7},"woeid":116545}, //End of nested JSON Object //End of JSON Object //Start of another JSON Object {"name":"Jackson","url":"http://where.yahooapis.com/v1/place/2428184","placeType":{"name":"Town","code":7},"parentid":23424977,"woeid":2428184} //End of another JSON Object ] //End of JSON Array
Creating JSON Data Using The JSON Object Model API
We have already seen how to parse the JSON data using the JSON Object Model API. Lets now look at how to create the JSON data using the JSON Object Model API. The following classes and interfaces from the API will be used for creating the data:
- Json: Factory class for creating JSON processing objects. This class provides the most commonly used methods for creating these objects and their corresponding factories. The factory classes provide all the various ways to create these objects.
- JsonArray: JsonArray represents an immutable JSON array (an ordered sequence of zero or more values). It also provides an unmodifiable list view of the values in the array.
- JsonObject: JsonObject class represents an immutable JSON object value (an unordered collection of zero or more name/value pairs). It also provides unmodifiable map view to the JSON object name/value mappings.
- JsonArrayBuilder: A builder for creating JsonArray models from scratch. This interface initializes an empty JSON array model and provides methods to add values to the array model and to return the resulting array. The methods in this class can be chained to add multiple values to the array.
- JsonObjectBuilder: A builder for creating JsonObject models from scratch. This interface initializes an empty JSON object model and provides methods to add name/value pairs to the object model and to return the resulting object. The methods in this class can be chained to add multiple name/value pairs to the object.
- JsonWriter: Writes a JSON object or array structure to an output source.
If you happen to read the article on parsing the JSON data using Object Model API you will notice that the classes used in both the places are exactly similar and the only difference being that in the parsing scenario we make use of the readers and in the creating scenario we make use of the builders. This API also uses the approach of Method chaining which is also similar to the Builder Pattern to create the object tree representing the JSON data. Unlike the Streaming API where we have the JSON data being buffered in the stream, in this Object Model API we are continuously building the object tree in the memory which represents the JSON data. We need to make use of a JsonWriter
to produce the JSON data an output stream. And this Object Model API supports the same data types supported by the Streaming API. Lets look at the code which is used to create the JSON data using Object Model API:
private static void buildJsonUsingObjectModelApi() { System.out.println("Json Building using Object Model API"); JsonArray jsonArray = //Create an Array Builder to build an JSON Array Json.createArrayBuilder() .add(Json.createObjectBuilder()//Create an Object builder to build JSON Object .add("parentid", 23424900) .add("name","Jackson") .add("url", "http://where.yahooapis.com/v1/place/2428184") .add("placeType", Json.createObjectBuilder()//Another nested JSON Object .add("name", "Town") .add("code",7) ) .add("woeid", 116545) .build()//The JSON Object completely constructed. ) .add(Json.createObjectBuilder()//Another object builder to build JSON Object. .add("name","Mexico City") .add("url", "http://where.yahooapis.com/v1/place/116545") .add("placeType", Json.createObjectBuilder() .add("name", "Town") .add("code",7) ) .add("parentid", 23424977) .add("woeid", 2428184) .build() ) .build(); StringWriter writer = new StringWriter(); //Extracting the JSON data from the JSON object tree into the string. Json.createWriter(writer).writeArray(jsonArray); System.out.println(writer.toString()); }
The output produced by the above code is:
Json Building using Object Model API [{"parentid":23424900,"name":"Jackson","url":"http://where.yahooapis.com/v1/place/2428184","placeType":{"name":"Town","code":7},"woeid":116545},{"name":"Mexico City","url":"http://where.yahooapis.com/v1/place/116545","placeType":{"name":"Town","code":7},"parentid":23424977,"woeid":2428184}]
When To Use Streaming API and Object Model API
- If you want the JSON data to be written to a character stream like a file or to a byte stream then the Streaming API will be the best choice as it directly perform the writing operation into the buffer without constructing the object tree in the memory i.e there is not intermediate form generated before the final JSON data is created.
- If you want to hold the JSON data as an object tree in the memory i.e not write to any stream but store the tree in the memory so that one can reuse the JSON data without need to reparse it or one can also serialize the object tree to persist/save the JSON data. Here the JSON data will be represented in the form of an object tree.
The Java JSON API (JSR 353) Example Source code
The complete executable source code for the above example without the comments is:
import java.io.StringWriter; import javax.json.Json; import javax.json.JsonArray; import javax.json.stream.JsonGenerator; public class JsonApiDemo { public static void main(String[] args) { buildJsonUsingStreamingApi(); buildJsonUsingObjectModelApi(); } private static void buildJsonUsingStreamingApi() { StringWriter writer = new StringWriter(); JsonGenerator generator = Json.createGenerator(writer); generator.writeStartArray() .writeStartObject() .write("parentid", 23424900) .write("name","Mexico City") .write("url", "http://where.yahooapis.com/v1/place/116545") .writeStartObject("placeType") .write("name","Town") .write("code", 7) .writeEnd() .write("woeid", 116545) .writeEnd() .writeStartObject() .write("name","Jackson") .write("url", "http://where.yahooapis.com/v1/place/2428184") .writeStartObject("placeType") .write("name","Town") .write("code", 7) .writeEnd() .write("parentid", 23424977) .write("woeid", 2428184) .writeEnd() .writeEnd(); generator.flush(); System.out.println(writer.toString()); } private static void buildJsonUsingObjectModelApi() { System.out.println("Json Building using Object Model API"); JsonArray jsonArray = Json.createArrayBuilder() .add(Json.createObjectBuilder() .add("parentid", 23424900) .add("name","Jackson") .add("url", "http://where.yahooapis.com/v1/place/2428184") .add("placeType", Json.createObjectBuilder() .add("name", "Town") .add("code",7)) .add("woeid", 116545) .build()) .add(Json.createObjectBuilder() .add("name","Mexico City") .add("url", "http://where.yahooapis.com/v1/place/116545") .add("placeType", Json.createObjectBuilder() .add("name", "Town") .add("code",7)) .add("parentid", 23424977) .add("woeid", 2428184) .build()) .build(); StringWriter writer = new StringWriter(); Json.createWriter(writer).writeArray(jsonArray); System.out.println(writer.toString()); } }
And the output is:
[{"parentid":23424900,"name":"Mexico City","url":"http://where.yahooapis.com/v1/place/116545","placeType":{"name":"Town","code":7},"woeid":116545},{"name":"Jackson","url":"http://where.yahooapis.com/v1/place/2428184","placeType":{"name":"Town","code":7},"parentid":23424977,"woeid":2428184}] Json Building using Object Model API [{"parentid":23424900,"name":"Jackson","url":"http://where.yahooapis.com/v1/place/2428184","placeType":{"name":"Town","code":7},"woeid":116545},{"name":"Mexico City","url":"http://where.yahooapis.com/v1/place/116545","placeType":{"name":"Town","code":7},"parentid":23424977,"woeid":2428184}]