Working with JSON Arrays using Jakarta JSON API

JSON arrays are a fundamental data structure in JSON, used to store collections of values or objects. Java provides the JsonArray and JsonArrayBuilder classes from the Jakarta JSON API to efficiently create, manipulate, and parse JSON arrays. It also provides methods to parse a JSON Array into a Java Collection. In this tutorial we will see both options with practical examples

Introduction to JSON Arrays in Java

JSON (JavaScript Object Notation) arrays are a collection of values, ordered by index, and enclosed within square brackets []. In Java, the Jakarta JSON API provides the JsonArray and JsonArrayBuilder classes to handle JSON arrays. On the other hand, you can use the getJsonArray method of the JsonObject Class to parse a JSON Array into a Java Collection. Let’s see both options in detail.

Using JsonArrayBuilder:

The JsonArrayBuilder class provides a fluent API for constructing JSON arrays in a more concise manner. To create a new JsonArrayBuilder, simply instantiate the class:

JsonArrayBuilder builder = new JsonArrayBuilder();

Then, you can add elements using various methods of this class. For example with the add method:

builder.add("Apple");
builder.add("Banana");
builder.add("Orange");

Once you’ve added all elements to the builder, you can convert it to a JsonArray instance using the build() method:

JsonArray jsonArray = arrayBuilder.build();

Now that you have a grasp on the basics of this Class, let’s see a complete example which shows how to create a JSON Document which includes an Array of JSON Documents in it:

JSON Array Java step-by-step guide

The following JBang Java Class contains the creation of the JSON Array and declares the required dependencies at the top of the script:

//usr/bin/env jbang "$0" "$@" ; exit $?
//DEPS jakarta.json.bind:jakarta.json.bind-api:3.0.0
//DEPS org.eclipse:yasson:3.0.3

import jakarta.json.Json;
import jakarta.json.JsonArray;
import jakarta.json.JsonArrayBuilder;
import jakarta.json.JsonObject;
import jakarta.json.JsonObjectBuilder;
 

public class JSONArrayExample {
    public static void main(String[] args) {
        // Create Order JSON object
        JsonObject order1 = createOrderJSON("1001", 500, "Model A");
        JsonObject order2 = createOrderJSON("1002", 750, "Model B");
        
        // Create Orders JSON array
        JsonArrayBuilder ordersArrayBuilder = Json.createArrayBuilder();
        ordersArrayBuilder.add(order1);
        ordersArrayBuilder.add(order2);
        // Build the Orders JSON array
        JsonArray ordersArray = ordersArrayBuilder.build();
        
        // Create Customer JSON object
        JsonObject customer = createCustomerJSON("John Doe", "123 Main St", ordersArray);
        
        // Print the Customer JSON object
        System.out.println("Customer JSON: " + customer);
    }

    // Method to create Order JSON object
    private static JsonObject createOrderJSON(String orderId, int price, String model) {
        JsonObjectBuilder orderBuilder = Json.createObjectBuilder();
        orderBuilder.add("orderId", orderId);
        orderBuilder.add("price", price);
        orderBuilder.add("model", model);
        return orderBuilder.build();
    }

    // Method to create Customer JSON object
    private static JsonObject createCustomerJSON(String name, String address, JsonArray orders) {
        JsonObjectBuilder customerBuilder = Json.createObjectBuilder();
        customerBuilder.add("name", name);
        customerBuilder.add("address", address);
        customerBuilder.add("orders", orders);
        return customerBuilder.build();
    }
}

By running the script, you should be able to see the JSON text as output.

$ jbang JSONArrayExample.java
Customer JSON: {"name":"John Doe","address":"123 Main St","orders":[{"orderId":"1001","price":500,"model":"Model A"},{"orderId":"1002","price":750,"model":"Model B"}]}

If you are new to JBang, you can head to this article for more information: JBang: Create Java scripts like a pro

Parsing a JSON Array to Java Collections

On the other hand, if you need to apply the reverse strategy, that is converting a JSON Array to a Java Collection, you can use the getJsonArray method of the JsonObject Class. For example:

private static Customer parseCustomerFromJSON(String json) {
        try (JsonReader reader = Json.createReader(new StringReader(json))) {
            JsonObject customerObject = reader.readObject();
            String name = customerObject.getString("name");
            String address = customerObject.getString("address");
            List<Order> orders = parseOrders(customerObject.getJsonArray("orders"));
            return new Customer(name, address, orders);
        }
}

In the above example, we are parsing an array of Orders into the Order Java Class or Record. The full code follows here:

//usr/bin/env jbang "$0" "$@" ; exit $?
//DEPS jakarta.json.bind:jakarta.json.bind-api:3.0.0
//DEPS org.eclipse:yasson:3.0.3

import jakarta.json.Json;
import jakarta.json.JsonArray;
import jakarta.json.JsonObject;
import jakarta.json.JsonReader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;

public class JSONToJavaRecords {
    public static void main(String[] args) {
        // Simulated JSON data
        String jsonInput = "{\"name\":\"John Doe\",\"address\":\"123 Main St\",\"orders\":[{\"orderId\":\"1001\",\"price\":500,\"model\":\"Model A\"},{\"orderId\":\"1002\",\"price\":750,\"model\":\"Model B\"}]}";
        
        // Convert JSON string to Java objects using Java Records
        Customer customer = parseCustomerFromJSON(jsonInput);
        
        // Display the parsed Java objects
        System.out.println("Customer Name: " + customer.name());
        System.out.println("Customer Address: " + customer.address());
        for (Order order : customer.orders()) {
            System.out.println("Order ID: " + order.orderId() + ", Price: " + order.price() + ", Model: " + order.model());
        }
    }

    // Method to parse JSON into Customer Java Record
    private static Customer parseCustomerFromJSON(String json) {
        try (JsonReader reader = Json.createReader(new StringReader(json))) {
            JsonObject customerObject = reader.readObject();
            String name = customerObject.getString("name");
            String address = customerObject.getString("address");
            List<Order> orders = parseOrders(customerObject.getJsonArray("orders"));
            return new Customer(name, address, orders);
        }
    }

    // Method to parse JSON array into List<Order>
    private static List<Order> parseOrders(JsonArray ordersArray) {
        List<Order> orders = new ArrayList<>();
        for (JsonObject orderObject : ordersArray.getValuesAs(JsonObject.class)) {
            String orderId = orderObject.getString("orderId");
            int price = orderObject.getInt("price");
            String model = orderObject.getString("model");
            orders.add(new Order(orderId, price, model));
        }
        return orders;
    }

    // Define Java Records for Customer and Order
    record Customer(String name, String address, List<Order> orders) {}
    record Order(String orderId, int price, String model) {}
}

You can run the Class and verify that it prints the Customer Record, containing the List of Orders:

$ jbang JSONToJavaRecords.java

Customer Name: John Doe
Customer Address: 123 Main St
Order ID: 1001, Price: 500, Model: Model A
Order ID: 1002, Price: 750, Model: Model B

Passing JSON Arrays in REST Services

JSON arrays are frequently used to represent collections of data in RESTful APIs. There are two main approaches to passing JSON arrays as parameters in REST services:

  1. Passing JSON Arrays in the Body as a POST Request: This approach is considered the preferred method for sending JSON data to a REST service. It ensures that the JSON data is properly formatted and avoids encoding issues.

To pass a JSON array in the body as a POST request, use the POST method and set the Content-Type header to application/json. The JSON data should be in the request body.

For example, the following curl command sends a JSON array named fruits containing the values "apple", "banana", and "grape" to a REST service:

curl -X POST -H "Content-Type: application/json" -d '{"fruits": ["apple", "banana", "grape"]}' http://localhost:8080/myEndpoint
  1. Passing JSON Arrays as Parameters in the URL: This approach involves encoding the JSON array into a URL query parameter. While less common, it can be useful when the JSON array is relatively small.

To pass a JSON array as a parameter in the URL, use the @QueryParam annotation in the REST service class. The JSON array should be encoded using the URLEncoder class. For example:

@GET
@Consumes({ MediaType.APPLICATION_JSON })
public String myMethod(@QueryParam("jsonArray") String jsonArray) throws  Exception {
        // Decode the JSON array from the URL parameter
        String decodedJsonArray = URLDecoder.decode(jsonArray, "UTF-8");

        // Parse the JSON array into a JsonArray object
	 Customer customer = parseCustomerFromJSON(decodedJsonArray);
	
.....
}

On the Client side, you should encode as well the JSON input parameter. For example, consider the following JSON:

{"name":"John Doe","address":"123 Main St","orders":[{"orderId":"1001","price":500,"model":"Model A"},{"orderId":"1002","price":750,"model":"Model B"}]}

It should be sent as follows:

curl http://localhost:8080/rest-demo/rest/hello?jsonArray="%7B%22name%22%3A%22John+Doe%22%2C%22address%22%3A%22123+Main+St%22%2C%22orders%22%3A%5B%7B%22orderId%22%3A%221001%22%2C%22price%22%3A500%2C%22model%22%3A%22Model+A%22%7D%2C%7B%22orderId%22%3A%221002%22%2C%22price%22%3A750%2C%22model%22%3A%22Model+B%22%7D%5D%7D"

Conclusion

Understanding and effectively using JSON arrays in Java via the Jakarta JSON API is crucial for handling structured data efficiently. The JsonArray and JsonArrayBuilder classes offer versatile tools for creating, manipulating, and parsing JSON arrays. In this tutorial we have also discussed the best options to pass a JSON Array as parameter in a REST Service.