JSON-P

JSR-353 JSON Processing (JSON-P) is the major addition to the Java EE 7 specification, because today's online businesses and institutions rely on this protocol for multiple channel architecture. It has the ability to service many media types such as web, e-mail, voice, data communication, and others, with a single source of business truth: the data service interface. Moreover, these services tend to be RESTful architectural endpoints rather than the Web-Services SOAP variety that drove the industry a decade earlier (circa 2003).

JSON-P is actually made up of two parts: a memory efficient streaming and an object model API.

Streaming

The streaming part of the JSON-P API is very useful for picking out bits and pieces of JSON from a large document without consuming a vast amount of memory. This is quite a boon if your application handles multitude RESTful over HTTP requests and the volume and size is big. The parsing side with streaming, then, is good.

Of course, applications also want to send JSON documents out to the clients and the output world. For those circumstances where the applications are volume broadcasting JSON documents to a swarm of waiting consumers, then a memory efficient way of sending data is also rather useful for server-side endpoints that must handle scale and unpredictability. The following screenshot shows the streaming part of the JSON-P API:

Streaming

Parsing JSON with Streaming API

Parsing JSON begins with the Java package javax.json.stream and the classes JsonParser and JsonParserFactory. The utility class javax.json.Json has a few methods to create a JsonParser from a java.io.InputStream or java.io.Reader. The parser reads JSON as a stream and returns a set of read-only events. This manner is very memory efficient for consuming JSON, because the data structures are only briefly kept during the parsing phrase. The feel of the API is similar to JAXP (Java for XML Processing).

Here is an Arquillian integration test that demonstrates parsing from JSON documented on the Wikipedia on JSON page:

@RunWith(Arquillian.class)
public class JSONPStreamingAPITest {
    @Deployment
    public static JavaArchive createDeployment() { /*...*/ }

    static String TEST_JSON =
        "{
" +
        "    "firstName": "John",
" +
        "    "lastName": "Smith",
" +
        "    "age": 25,
" +
        "    "address": {
" +
        "        "streetAddress": "21 2nd Street",
" +
        "        "city": "New York",
" +
        "        "state": "NY",
" +
        "        "postalCode": 10021
" +
        "    }
" +
        "}"
        ;

    @Test
    public void shouldParseJSONSchema() {
        StringReader sreader = new StringReader(TEST_JSON);
        JsonParser parser = Json.createParser(sreader);
        JsonParser.Event event = parser.next();
        assertEquals(START_OBJECT, event);
        while (parser.hasNext()) {
            event = parser.next();
            if ( event == KEY_NAME) {
                switch (parser.getString()) {
                  case "firstName":
                    parser.next();
                    assertThat( parser.getString(), is("John"));
                        break;
                  case "lastName":
                    parser.next();
                    assertThat( parser.getString(), is("Smith"));
                        break;
                  case "age":
                    parser.next();
                    assertThat( parser.getInt(), is(25));
                        break;
                }
            }
        }
    }
}

In order to determine the location of the parser as it processes each part of the JSON stream, we must inspect JsonParser.Event, which is actually an enumeration. This enum has the following values: START_ARRAY, END_ARRAY, START_OBJECT, END_OBJECT, VALUE_FALSE, VALUE_NULL, VALUE_TRUE, KEY_NAME, VALUE_STRING, and VALUE_NUMBER. Each value represents the parser's marker.

Generating JSON with Streaming API

The JSON-P can also generate JSON in memory efficient fashion. Java interfaces are JsonGenerator and JsonGeneratorFactory, and they are also part of the package javax.json.stream.

Writing JSON output with the Streaming API is much easier than the parsing. Developers should reach for one of the Json.createGenerator() methods that accepts either a java.io.OutputStream or a java.io.Writer.

Here is a unit test method to demonstrate writing JSON using streaming mode:

    @Test
    public void shouldGenerateJSON() {
        StringWriter swriter = new StringWriter();
        try (JsonGenerator generator =
                     Json.createGenerator(swriter)) {
            generator
              .writeStartObject()
                 .write("artist", "Daft Punk")
                 .write("album", "Random Access Memories")
                 .write("year", 2013)
                 .writeStartArray("collaborators")
                    .writeStartObject()
                      .write("firstName", "Nile")
                      .write("lastName", "Rodgers")
                    .writeEnd()
                    .writeStartObject()
                      .write("firstName", "Giorgio")
                      .write("lastName", "Moroder")
                    .writeEnd()
                 .writeEnd()
              .writeEnd();
        }
        
        String expected = "{"artist":"Daft Punk"," +
        ""album":"Random Access Memories","year":2013,"" +
        "collaborators":[{"firstName":"Nile"," +
        ""lastName":"Rodgers"},{"firstName":" +
        ""Giorgio","lastName":"Moroder"}]}";
        assertThat(swriter.toString().length(), is(not(0)));
        assertThat(swriter.toString(), is(expected));
    }

The key methods on the JsonGenerator are writeStartObject(), writeStartArray(), and the overloaded variations of write().Each JSON object or array must be terminated with a writeEnd() call. Of course the API ensures that the JSON schema is followed exactly.

Object model

The JSON-P has a second form that reads and writes JSON documents wholly in memory. The larger your JSON document, the greater the amount of memory that is consumed.

Parsing JSON with the object model

Parsing JSON from a string representation is relatively straightforward. Your application requires a javax.json.JsonReader instance, which can be created from the Json static utility class. From there, it is just a case of building a JSON schema as an internal tree data structure.

The object model is very convenient to build structures. It can also be useful to aggregate responses together from separate JSON documents into another larger structure. When Java SE 8 arrives with the Lambdas then we could see certain applications take advantage of parallel JSON document generation with the fork-join model.

This is a unit test that illustrates how to parse JSON with the Object Model:

@RunWith(Arquillian.class)
public class JSONPObjectAPITest {
    @Deployment
    public static JavaArchive createDeployment() { /*...*/ }

    static String TEST_JSON =
        "{
" +
        "    "firstName": "John",
" +
        "    "lastName": "Smith",
" +
        "    "age": 25,
" +
        /*... */ + "}"
        ;

    @Test
    public void shouldParseJSONSchema() {
        StringReader sreader = new StringReader(TEST_JSON);
        JsonReader reader = Json.createReader(sreader);
        JsonObject obj = reader.readObject();
        assertThat( obj.getString("firstName"), is("John"));
        assertThat( obj.getString("lastName"), is("Smith"));
        assertThat( obj.getInt("age"), is(25));
        JsonObject address = obj.getJsonObject("address");
        assertNotNull(address);
        assertThat( address.getString("streetAddress"), is("21 2nd Street"));
        assertThat( address.getString("city"), is("New York"));
        assertThat( address.getString("state"), is("NY"));
        assertThat( address.getInt("postalCode"), is(10021));
    }
}

The JsonReader has two principal methods: readObject(), which you call when the application expects a JSON object, and the alternative readArray(), which handles JSON arrays. Assuming there are no exceptions and the input JSON is expected, then your application reads the attribute key and values. JsonObject has several methods such as getString(), getInt(), and getBoolean() and there are default value variants of these methods too. JsonArray has more or less the same methods except they take an index argument for convenience.

Incidentally, JsonObject is a type of Map<String,JsonValue> and that means we can query the existence of JSONP attribute keys. The super class of JsonObject and JsonArray is the JsonValue and their direct ancestor type is a JsonStructure.

Generating JSON with the object model

Generating JSON with the object model API is a piece of cake too. It closely resembles the Streaming API in concept. The key types are javax.json.JsonWriter, JsonBuilderFactory, and JsonObjectBuilder.

Here is a final unit test that demonstrates writing JSON with the object model:

@Test
public void shouldWriteJSON() {
    JsonBuilderFactory factory = Json.createBuilderFactory(null);
    JsonObjectBuilder builder = factory.createObjectBuilder();
    JsonObject obj =
    builder.add("artist", "Daft Punk")
        .add("album", "Random Access Memories")
        .add("year", 2013)
        .add("collaborators",
            factory.createArrayBuilder()
            .add( factory.createObjectBuilder()
                .add("firstName", "Nile")
                .add("lastName", "Rodgers")
                .build())
            .add( factory.createObjectBuilder()
                .add("firstName", "Giorgio")
                .add("lastName", "Moroder")
                .build())
            .build()
        )
        .build();

    StringWriter swriter = new StringWriter();
    try (JsonWriter writer =
             Json.createWriter(swriter)) {
        writer.writeObject(obj);
    }
    String expected = "{"artist":"Daft Punk"," +
    ""album":"Random Access Memories","year":2013,"" +
    "collaborators":[{"firstName":"Nile"," +
    ""lastName":"Rodgers"},{"firstName":" +
    ""Giorgio","lastName":"Moroder"}]}";
    assertThat(swriter.toString(), is(expected));
}

First, we create a JsonBuilderFactory from the Json static utility class. We can optionally pass in a property map. For example, if we wanted to print the JSON output prettily, we could pass in a map collection to control the configuration like this:

JsonBuilderFactory factory = Json.createBuilderFactory(
    new HashMap<String, Object>() {{
        put(JsonGenerator.PRETTY_PRINTING, true);
    }});

We create a JsonObjectBuilder instance from the factory. The JsonObjectBuilder follows the builder pattern style. For each JSON object created as an intermediate instance, it has to be completed with the call to build(), which changes the internal mode of instance to be read-only, thereby freezing the state of JsonValue. Each attribute is added to the JSON object and arrays are added by creating another JSON instance, either a JsonArray or a JsonObject, which are created from the factory.

The javax.json.JsonWriter is the type responsible for writing the JSON internal instances into either a java.io.OutputStream or java.io.Writer.

In short, the static utility class Json is the main entry point to JSON-P. Beneath the infrastructure lies another type javax.json.spi.JsonProvider that controls the implementation loaded at a runtime. At the time of writing, only GlassFish has a JSON-P provider, but because the JsonProvider follows the java.util.ServiceLoader mechanism, this means that an alternative one can be defined at deployment. If the application supplies a META-INF/services/javax.json.spi.JsonProvider file with a single line that states the fully qualified class name of the new provider, then it will be used instead. Bean validation follows the same mechanism.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.186.83