JSON Processing

We are working on a fresh, updated Jakarta EE Tutorial. This section hasn’t yet been updated.

This chapter describes Jakarta JSON Processing. JSON is a data exchange format widely used in web services and other connected applications. Jakarta JSON Processing provides an API to parse, transform, and query JSON data using the object model or the streaming model.

Introduction to JSON

JSON is a text-based data exchange format derived from JavaScript that is used in web services and other connected applications. The following sections provide an introduction to JSON syntax, an overview of JSON uses, and a description of the most common approaches to generate and parse JSON.

JSON Syntax

JSON defines only two data structures: objects and arrays. An object is a set of name-value pairs, and an array is a list of values. JSON defines seven value types: string, number, object, array, true, false, and null.

The following example shows JSON data for a sample object that contains name-value pairs. The value for the name "phoneNumbers" is an array whose elements are two objects.

{
   "firstName": "Duke",
   "lastName": "Java",
   "age": 18,
   "streetAddress": "100 Internet Dr",
   "city": "JavaTown",
   "state": "JA",
   "postalCode": "12345",
   "phoneNumbers": [
      { "Mobile": "111-111-1111" },
      { "Home": "222-222-2222" }
   ]
}

JSON has the following syntax.

  • Objects are enclosed in braces ({}), their name-value pairs are separated by a comma (,), and the name and value in a pair are separated by a colon (:). Names in an object are strings, whereas values may be of any of the seven value types, including another object or an array.

  • Arrays are enclosed in brackets ([]), and their values are separated by a comma (,). Each value in an array may be of a different type, including another array or an object.

  • When objects and arrays contain other objects or arrays, the data has a tree-like structure.

Uses of JSON

JSON is often used as a common format to serialize and deserialize data in applications that communicate with each other over the Internet. These applications are created using different programming languages and run in very different environments. JSON is suited to this scenario because it is an open standard, it is easy to read and write, and it is more compact than other representations.

RESTful web services use JSON extensively as the format for the data inside requests and responses. The HTTP header used to indicate that the content of a request or a response is JSON data is

Content-Type: application/json

JSON representations are usually more compact than XML representations because JSON does not have closing tags. Unlike XML, JSON does not have a widely accepted schema for defining and validating the structure of JSON data.

Generating and Parsing JSON Data

For generating and parsing JSON data, there are two programming models, which are similar to those used for XML documents.

  • The object model creates a tree that represents the JSON data in memory. The tree can then be navigated, analyzed, or modified. This approach is the most flexible and allows for processing that requires access to the complete contents of the tree. However, it is often slower than the streaming model and requires more memory. The object model generates JSON output by navigating the entire tree at once.

  • The streaming model uses an event-based parser that reads JSON data one element at a time. The parser generates events and stops for processing when an object or an array begins or ends, when it finds a key, or when it finds a value. Each element can be processed or discarded by the application code, and then the parser proceeds to the next event. This approach is adequate for local processing, in which the processing of an element does not require information from the rest of the data. The streaming model generates JSON output to a given stream by making a function call with one element at a time.

There are many JSON generators and parsers available for different programming languages and environments. JSON Processing in the Jakarta EE Platform describes the functionality provided by Jakarta JSON Processing.

JSON Processing in the Jakarta EE Platform

Jakarta EE includes support for the Jakarta JSON Processing spec, which provides an API to parse, transform, and query JSON data using the object model or the streaming model described in Generating and Parsing JSON Data. Jakarta JSON Processing contains the following packages:

  • The jakarta.json package contains a reader interface, a writer interface, a model builder interface for the object model, and utility classes and Java types for JSON elements. This package also includes several classes that implement other JSON-related standards: JSON Pointer, JSON Patch, and JSON Merge Patch. These standards are used to retrieve, transform or manipulate values in an object model. Main Classes and Interfaces in jakarta.json lists the main classes and interfaces in this package.

  • The jakarta.json.stream package contains a parser interface and a generator interface for the streaming model. Main Classes and Interfaces in jakarta.json.stream lists the main classes and interfaces in this package.

  • The jakarta.json.spi package contains a Service Provider Interface (SPI) to plug in implementations for JSON processing objects. This package contains the JsonProvider class, which contains the methods that a service provider implements.

Main Classes and Interfaces in jakarta.json
Class or Interface Description

Json

Contains static methods to create instances of JSON parsers, builders, and generators. This class also contains methods to create parser, builder, and generator factory objects.

JsonReader

Reads JSON data from a stream and creates an object model in memory.

JsonObjectBuilder, JsonArrayBuilder

Create an object model or an array model in memory by adding elements from application code.

JsonWriter

Writes an object model from memory to a stream.

JsonValue

Represents an element (such as an object, an array, or a value) in JSON data.

JsonStructure

Represents an object or an array in JSON data. This interface is a subtype of JsonValue.

JsonObject, JsonArray

Represent an object or an array in JSON data. These two interfaces are subtypes of JsonStructure.

JsonPointer

Contains methods for operating on specific targets within JSON documents. The targets can be JsonValue, JsonObject, or JsonArray objects.

JsonPatch

An interface for supporting a sequence of operations to be applied to a target JSON resource. The operations are defined within a JSON patch document.

JsonMergePatch

An interface for supporting updates to target JSON resources. A JSON patch document is compared with the target resource to determine the specific set of change operations to be applied.

JsonString, JsonNumber

Represent data types for elements in JSON data. These two interfaces are subtypes of JsonValue.

JsonException

Indicates that a problem occurred during JSON processing.

Main Classes and Interfaces in jakarta.json.stream
Class or Interface Description

JsonParser

Represents an event-based parser that can read JSON data from a stream or from an object model.

JsonGenerator

Writes JSON data to a stream one element at a time.

Using the Object Model API

This section describes four use cases of the object model API: creating an object model from JSON data, creating an object model from application code, navigating an object model, and writing an object model to a stream.

Creating an Object Model from JSON Data

The following code demonstrates how to create an object model from JSON data in a text file:

import java.io.FileReader;
import jakarta.json.Json;
import jakarta.json.JsonReader;
import jakarta.json.JsonStructure;
...
JsonReader reader = Json.createReader(new FileReader("jsondata.txt"));
JsonStructure jsonst = reader.read();

The object reference jsonst can be either of type JsonObject or of type JsonArray, depending on the contents of the file. JsonObject and JsonArray are subtypes of JsonStructure. This reference represents the top of the tree and can be used to navigate the tree or to write it to a stream as JSON data.

Creating an Object Model from Application Code

The following code demonstrates how to create an object model from application code:

import jakarta.json.Json;
import jakarta.json.JsonObject;
...
JsonObject model = Json.createObjectBuilder()
   .add("firstName", "Duke")
   .add("lastName", "Java")
   .add("age", 18)
   .add("streetAddress", "100 Internet Dr")
   .add("city", "JavaTown")
   .add("state", "JA")
   .add("postalCode", "12345")
   .add("phoneNumbers", Json.createArrayBuilder()
      .add(Json.createObjectBuilder()
         .add("type", "mobile")
         .add("number", "111-111-1111"))
      .add(Json.createObjectBuilder()
         .add("type", "home")
         .add("number", "222-222-2222")))
   .build();

The object reference model represents the top of the tree, which is created by nesting calls to the add methods and built by calling the build method. The JsonObjectBuilder class contains the following add methods:

JsonObjectBuilder add(String name, BigDecimal value)
JsonObjectBuilder add(String name, BigInteger value)
JsonObjectBuilder add(String name, boolean value)
JsonObjectBuilder add(String name, double value)
JsonObjectBuilder add(String name, int value)
JsonObjectBuilder add(String name, JsonArrayBuilder builder)
JsonObjectBuilder add(String name, JsonObjectBuilder builder)
JsonObjectBuilder add(String name, JsonValue value)
JsonObjectBuilder add(String name, long value)
JsonObjectBuilder add(String name, String value)
JsonObjectBuilder addNull(String name)

The JsonArrayBuilder class contains similar add methods that do not have a name (key) parameter. You can nest arrays and objects by passing a new JsonArrayBuilder object or a new JsonObjectBuilder object to the corresponding add method, as shown in this example.

The resulting tree represents the JSON data from JSON Syntax.

Navigating an Object Model

The following code demonstrates a simple approach to navigating an object model:

import jakarta.json.JsonValue;
import jakarta.json.JsonObject;
import jakarta.json.JsonArray;
import jakarta.json.JsonNumber;
import jakarta.json.JsonString;
...
public static void navigateTree(JsonValue tree, String key) {
   if (key != null)
      System.out.print("Key " + key + ": ");
   switch(tree.getValueType()) {
      case OBJECT:
         System.out.println("OBJECT");
         JsonObject object = (JsonObject) tree;
         for (String name : object.keySet())
            navigateTree(object.get(name), name);
         break;
      case ARRAY:
         System.out.println("ARRAY");
         JsonArray array = (JsonArray) tree;
         for (JsonValue val : array)
            navigateTree(val, null);
         break;
      case STRING:
         JsonString st = (JsonString) tree;
         System.out.println("STRING " + st.getString());
         break;
      case NUMBER:
         JsonNumber num = (JsonNumber) tree;
         System.out.println("NUMBER " + num.toString());
         break;
      case TRUE:
      case FALSE:
      case NULL:
         System.out.println(tree.getValueType().toString());
         break;
   }
}

The method navigateTree can be used with the models built in Creating an Object Model from JSON Data and Creating an Object Model from Application Code as follows:

navigateTree(model, null);

The navigateTree method takes two arguments: a JSON element and a key. The key is used only to help print the key-value pairs inside objects. Elements in a tree are represented by the JsonValue type. If the element is an object or an array, a new call to this method is made for every element contained in the object or array. If the element is a value, it is printed to the standard output.

The JsonValue.getValueType method identifies the element as an object, an array, or a value. For objects, the JsonObject.keySet method returns a set of strings that contains the keys in the object, and the JsonObject.get(String name) method returns the value of the element whose key is name. For arrays, JsonArray implements the List<JsonValue> interface. You can use enhanced for loops with the Set<String> instance returned by JsonObject.keySet and with instances of JsonArray, as shown in this example.

The navigateTree method for the model built in Creating an Object Model from Application Code produces the following output:

OBJECT
   Key firstName: STRING Duke
   Key lastName: STRING Java
   Key age: NUMBER 18
   Key streetAddress: STRING 100 Internet Dr
   Key city: STRING JavaTown
   Key state: STRING JA
   Key postalCode: STRING 12345
   Key phoneNumbers: ARRAY
      OBJECT
         Key type: STRING mobile
         Key number: STRING 111-111-1111
      OBJECT
         Key type: STRING home
         Key number: STRING 222-222-2222

Writing an Object Model to a Stream

The object models created in Creating an Object Model from JSON Data and Creating an Object Model from Application Code can be written to a stream using the JsonWriter class as follows:

import java.io.StringWriter;
import jakarta.json.JsonWriter;
...
StringWriter stWriter = new StringWriter();
JsonWriter jsonWriter = Json.createWriter(stWriter);
jsonWriter.writeObject(model);
jsonWriter.close();

String jsonData = stWriter.toString();
System.out.println(jsonData);

The Json.createWriter method takes an output stream as a parameter. The JsonWriter.writeObject method writes the object to the stream. The JsonWriter.close method closes the underlying output stream.

The following example uses try-with-resources to close the JSON writer automatically:

StringWriter stWriter = new StringWriter();
try (JsonWriter jsonWriter = Json.createWriter(stWriter)) {
   jsonWriter.writeObject(model);
}

String jsonData = stWriter.toString();
System.out.println(jsonData);

Using the Streaming API

This section describes two use cases of the streaming API.

Reading JSON Data Using a Parser

The streaming API is the most efficient approach for parsing JSON text. The following code demonstrates how to create a JsonParser object and how to parse JSON data using events:

import jakarta.json.Json;
import jakarta.json.stream.JsonParser;
...
JsonParser parser = Json.createParser(new StringReader(jsonData));
while (parser.hasNext()) {
   JsonParser.Event event = parser.next();
   switch(event) {
      case START_ARRAY:
      case END_ARRAY:
      case START_OBJECT:
      case END_OBJECT:
      case VALUE_FALSE:
      case VALUE_NULL:
      case VALUE_TRUE:
         System.out.println(event.toString());
         break;
      case KEY_NAME:
         System.out.print(event.toString() + " " +
                          parser.getString() + " - ");
         break;
      case VALUE_STRING:
      case VALUE_NUMBER:
         System.out.println(event.toString() + " " +
                            parser.getString());
         break;
   }
}

This example consists of three steps.

  1. Obtain a parser instance by calling the Json.createParser static method.

  2. Iterate over the parser events with the JsonParser.hasNext and the JsonParser.next methods.

  3. Perform local processing for each element.

The example shows the ten possible event types from the parser. The parser’s next method advances it to the next event. For the event types KEY_NAME, VALUE_STRING, and VALUE_NUMBER, you can obtain the content of the element by calling the method JsonParser.getString. For VALUE_NUMBER events, you can also use the following methods:

  • JsonParser.isIntegralNumber

  • JsonParser.getInt

  • JsonParser.getLong

  • JsonParser.getBigDecimal

See the Jakarta EE API reference for the jakarta.json.stream.JsonParser interface for more information.

The output of this example is the following:

START_OBJECT
KEY_NAME firstName - VALUE_STRING Duke
KEY_NAME lastName - VALUE_STRING Java
KEY_NAME age - VALUE_NUMBER 18
KEY_NAME streetAddress - VALUE_STRING 100 Internet Dr
KEY_NAME city - VALUE_STRING JavaTown
KEY_NAME state - VALUE_STRING JA
KEY_NAME postalCode - VALUE_STRING 12345
KEY_NAME phoneNumbers - START_ARRAY
START_OBJECT
KEY_NAME type - VALUE_STRING mobile
KEY_NAME number - VALUE_STRING 111-111-1111
END_OBJECT
START_OBJECT
KEY_NAME type - VALUE_STRING home
KEY_NAME number - VALUE_STRING 222-222-2222
END_OBJECT
END_ARRAY
END_OBJECT

Writing JSON Data Using a Generator

The following code demonstrates how to write JSON data to a file using the streaming API:

FileWriter writer = new FileWriter("test.txt");
JsonGenerator gen = Json.createGenerator(writer);
gen.writeStartObject()
   .write("firstName", "Duke")
   .write("lastName", "Java")
   .write("age", 18)
   .write("streetAddress", "100 Internet Dr")
   .write("city", "JavaTown")
   .write("state", "JA")
   .write("postalCode", "12345")
   .writeStartArray("phoneNumbers")
      .writeStartObject()
         .write("type", "mobile")
         .write("number", "111-111-1111")
      .writeEnd()
      .writeStartObject()
         .write("type", "home")
         .write("number", "222-222-2222")
      .writeEnd()
   .writeEnd()
.writeEnd();
gen.close();

This example obtains a JSON generator by calling the Json.createGenerator static method, which takes a writer or an output stream as a parameter. The example writes JSON data to the test.txt file by nesting calls to the write, writeStartArray, writeStartObject, and writeEnd methods. The JsonGenerator.close method closes the underlying writer or output stream.

JSON in Jakarta EE RESTful Web Services

This section explains how the Jakarta JSON Processing is related to other Jakarta EE packages that provide JSON support for RESTful web services. See Building RESTful Web Services with Jakarta REST for more information on RESTful web services.

Jersey, the Jakarta RESTful Web Services implementation included in GlassFish Server, provides support for binding JSON data from RESTful resource methods to Java objects using Jakarta XML Binding, as described in Using Jakarta REST with Jakarta XML Binding in Jakarta REST: Advanced Topics and an Example. However, JSON support is not part of Jakarta RESTful Web Services or Jakarta XML Binding, so that procedure may not work for Jakarta EE implementations other than GlassFish Server.

You can still use the Jakarta JSON Processing with Jakarta RESTful Web Services resource methods. For more information, see the sample code for JSON Processing included with the Jakarta EE tutorial examples.

The jsonpmodel Example Application

This section describes how to build and run the jsonpmodel example application. This example is a web application that demonstrates how to create an object model from form data, how to parse JSON data, and how write JSON data using the object model API.

The jsonpmodel example application is in the jakartaee-examples/tutorial/web/jsonp/jsonpmodel directory.

Components of the jsonpmodel Example Application

The jsonpmodel example application contains the following files.

  • Three Jakarta Faces pages.

    • The index.xhtml page contains a form to collect information.

    • The modelcreated.xhtml page contains a text area that displays JSON data.

    • The parsejson.xhtml page contains a table that shows the elements of the object model.

  • The ObjectModelBean.java managed bean, which is a session-scoped managed bean that stores the data from the form and directs the navigation between the Facelets pages. This file also contains code that uses the JSON object model API.

The code used in ObjectModelBean.java to create an object model from the data in the form is similar to the example in Creating an Object Model from Application Code. The code to write JSON output from the model is similar to the example in Writing an Object Model to a Stream. The code to navigate the object model tree is similar to the example in Navigating an Object Model.

Running the jsonpmodel Example Application

This section describes how to run the jsonpmodel example application using NetBeans IDE and from the command line.

To Run the jsonpmodel Example Application Using NetBeans IDE

  1. Make sure that GlassFish Server has been started (see Starting and Stopping GlassFish Server).

  2. From the File menu, choose Open Project.

  3. In the Open Project dialog box, navigate to:

    jakartaee-examples/tutorial/web/jsonp
  4. Select the jsonpmodel folder.

  5. Click Open Project.

  6. In the Projects tab, right-click the jsonpmodel project and select Run.

    This command builds and packages the application into a WAR file (jsonpmodel.war) located in the target directory, deploys it to the server, and opens a web browser window with the following URL:

    http://localhost:8080/jsonpmodel/
  7. Edit the data on the page and click Create a JSON Object to submit the form. The following page shows a JSON object that contains the data from the form.

  8. Click Parse JSON. The following page contains a table that lists the nodes of the object model tree.

To Run the jsonpmodel Example Application Using Maven

  1. Make sure that GlassFish Server has been started (see Starting and Stopping GlassFish Server).

  2. In a terminal window, go to:

    jakartaee-examples/tutorial/web/jsonp/jsonpmodel
  3. Enter the following command to deploy the application:

    mvn install
  4. Open a web browser window and enter the following address:

    http://localhost:8080/jsonpmodel/
  5. Edit the data on the page and click Create a JSON Object to submit the form. The following page shows a JSON object that contains the data from the form.

  6. Click Parse JSON. The following page contains a table that lists the nodes of the object model tree.

The jsonpstreaming Example Application

This section describes how to build and run the jsonpstreaming example application. This example is a web application that demonstrates how to create JSON data from form data, how to parse JSON data, and how to write JSON output using the streaming API.

The jsonpstreaming example application is in the jakartaee-examples/tutorial/web/jsonp/jsonpstreaming directory.

Components of the jsonpstreaming Example Application

The jsonpstreaming example application contains the following files.

  • Three Jakarta Faces pages.

    • The index.xhtml page contains a form to collect information.

    • The filewritten.xhtml page contains a text area that displays JSON data.

    • The parsed.xhtml page contains a table that lists the events from the parser.

  • The StreamingBean.java managed bean, a session-scoped managed bean that stores the data from the form and directs the navigation between the Facelets pages. This file also contains code that uses the JSON streaming API.

The code used in StreamingBean.java to write JSON data to a file is similar to the example in Writing JSON Data Using a Generator. The code to parse JSON data from a file is similar to the example in Reading JSON Data Using a Parser.

Running the jsonpstreaming Example Application

This section describes how to run the jsonpstreaming example application using NetBeans IDE and from the command line.

To Run the jsonpstreaming Example Application Using NetBeans IDE

  1. Make sure that GlassFish Server has been started (see Starting and Stopping GlassFish Server).

  2. From the File menu, choose Open Project.

  3. In the Open Project dialog box, navigate to:

    jakartaee-examples/tutorial/web/jsonp
  4. Select the jsonpstreaming folder.

  5. Click Open Project.

  6. In the Projects tab, right-click the jsonpstreaming project and select Run.

    This command builds and packages the application into a WAR file (jsonpstreaming.war) located in the target directory, deploys it to the server, and opens a web browser window with the following URL:

    http://localhost:8080/jsonpstreaming/
  7. Edit the data on the page and click Write a JSON Object to a File to submit the form and write a JSON object to a text file. The following page shows the contents of the text file.

  8. Click Parse JSON from File. The following page contains a table that lists the parser events for the JSON data in the text file.

To Run the jsonpstreaming Example Application Using Maven

  1. Make sure that GlassFish Server has been started (see Starting and Stopping GlassFish Server).

  2. In a terminal window, go to:

    jakartaee-examples/tutorial/web/jsonp/jsonpstreaming/
  3. Enter the following command to deploy the application:

    mvn install
  4. Open a web browser window and enter the following URL:

    http://localhost:8080/jsonpstreaming/
  5. Edit the data on the page and click Write a JSON Object to a File to submit the form and write a JSON object to a text file. The following page shows the contents of the text file.

  6. Click Parse JSON from File. The following page contains a table that lists the parser events for the JSON data in the text file.

Further Information about the Jakarta JSON Processing

For more information on JSON processing in Jakarta EE, see the Jakarta JSON Processing specification: