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 theJsonProvider
class, which contains the methods that a service provider implements.
Class or Interface | Description |
---|---|
|
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. |
|
Reads JSON data from a stream and creates an object model in memory. |
|
Create an object model or an array model in memory by adding elements from application code. |
|
Writes an object model from memory to a stream. |
|
Represents an element (such as an object, an array, or a value) in JSON data. |
|
Represents an object or an array in JSON data.
This interface is a subtype of |
|
Represent an object or an array in JSON data.
These two interfaces are subtypes of |
|
Contains methods for operating on specific targets within JSON documents.
The targets can be |
|
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. |
|
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. |
|
Represent data types for elements in JSON data.
These two interfaces are subtypes of |
|
Indicates that a problem occurred during JSON processing. |
Class or Interface | Description |
---|---|
|
Represents an event-based parser that can read JSON data from a stream or from an object model. |
|
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.
-
Obtain a parser instance by calling the
Json.createParser
static method. -
Iterate over the parser events with the
JsonParser.hasNext
and theJsonParser.next
methods. -
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
-
Make sure that GlassFish Server has been started (see Starting and Stopping GlassFish Server).
-
From the File menu, choose Open Project.
-
In the Open Project dialog box, navigate to:
jakartaee-examples/tutorial/web/jsonp
-
Select the
jsonpmodel
folder. -
Click Open Project.
-
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 thetarget
directory, deploys it to the server, and opens a web browser window with the following URL:http://localhost:8080/jsonpmodel/
-
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.
-
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
-
Make sure that GlassFish Server has been started (see Starting and Stopping GlassFish Server).
-
In a terminal window, go to:
jakartaee-examples/tutorial/web/jsonp/jsonpmodel
-
Enter the following command to deploy the application:
mvn install
-
Open a web browser window and enter the following address:
http://localhost:8080/jsonpmodel/
-
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.
-
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
-
Make sure that GlassFish Server has been started (see Starting and Stopping GlassFish Server).
-
From the File menu, choose Open Project.
-
In the Open Project dialog box, navigate to:
jakartaee-examples/tutorial/web/jsonp
-
Select the
jsonpstreaming
folder. -
Click Open Project.
-
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 thetarget
directory, deploys it to the server, and opens a web browser window with the following URL:http://localhost:8080/jsonpstreaming/
-
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.
-
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
-
Make sure that GlassFish Server has been started (see Starting and Stopping GlassFish Server).
-
In a terminal window, go to:
jakartaee-examples/tutorial/web/jsonp/jsonpstreaming/
-
Enter the following command to deploy the application:
mvn install
-
Open a web browser window and enter the following URL:
http://localhost:8080/jsonpstreaming/
-
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.
-
Click Parse JSON from File. The following page contains a table that lists the parser events for the JSON data in the text file.