Course – LS (cat=JSON/Jackson)

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE

1. Overview

Working with JSON (JavaScript Objеct Notation) in Java often involves using librariеs like Jackson, which provides various classеs to rеprеsеnt this type of data, such as JsonNodе, ObjectNode, and ArrayNode.

In this tutorial, we’ll еxplorе different approaches to simplifying array operations on a JsonNodе without explicitly casting it to ArrayNode in Java. This is necessary when manipulating the data directly in our code.

2. Understanding JsonNode and ArrayNode

JsonNode is an abstract class in the Jackson library that represents a node in the JSON tree. It’s the base class for all nodes and is capable of storing different types of data, including objects, arrays, strings, numbers, booleans, and null values. JsonNode instances are immutable, meaning we can’t set properties on them.

ArrayNode is a specific type of JsonNode that represents a JSON array. It extends the functionality of JsonNode to include methods for working with arrays, such as adding, removing, and accessing elements by index.

3. Using JsonNode‘s get() Method

By using JsonNode methods, we can transform it to ArrayNode without explicitly casting. This approach is useful when we need to perform specific actions or validations on each element within a JSON array:

@Test
void givenJsonNode_whenUsingJsonNodeMethods_thenConvertToArrayNode() throws JsonProcessingException {
    int count = 0;
    String json = "{\"objects\": [\"One\", \"Two\", \"Three\"]}";
    JsonNode arrayNode = new ObjectMapper().readTree(json).get("objects");
    assertNotNull(arrayNode, "The 'objects' array should not be null");
    assertTrue(arrayNode.isArray(), "The 'objects' should be an array");
    if (arrayNode.isArray()) {
        for (JsonNode objNode : arrayNode) {
            assertNotNull(objNode, "Array element should not be null");
            count++;
         }
    }
    assertEquals(3, count, "The 'objects' array should have 3 elements");
}

This approach also ensures that we’re working with an array structure before attempting to iterate over its elements, helping prevent potential runtime errors related to unexpected JSON structures.

4. Using createArrayNode()

In Jackson, we can create a JSON object using the createObjectNode() method. Similarly, we can use the createArrayNode() method of the ObjectMapper class to create a JSON Array. The method createArrayNode() will return a reference of ArrayNode class:

@Test
void givenJsonNode_whenUsingCreateArrayNode_thenConvertToArrayNode() throws Exception {
    ObjectMapper objectMapper = new ObjectMapper();
    JsonNode originalJsonNode = objectMapper.readTree("{\"objects\": [\"One\", \"Two\", \"Three\"]}");
    ArrayNode arrayNode = objectMapper.createArrayNode();
    originalJsonNode.get("objects").elements().forEachRemaining(arrayNode::add);
    assertEquals("[\"One\",\"Two\",\"Three\"]", arrayNode.toString());
}

This approach is useful when we need to transform a specific part of a JSON structure into an ArrayNode without explicitly casting. Creating an ArrayNode explicitly communicates that we’re working with an Array, making the code more readable and expressive.

5. Using StreamSuppport Class

StreamSupport is a utility class that provides static methods for creating Streams and Spliterators over various data structures, including collections, arrays, and specialized iterators. The string is deserialized into a JsonNode object using ObjectMapper. Here, we’re creating a Stream from the Spliterator of the objects array, and the elements are collected into the List<JsonNode>:

@Test
void givenJsonNode_whenUsingStreamSupport_thenConvertToArrayNode() throws Exception {
    String json = "{\"objects\": [\"One\", \"Two\", \"Three\"]}";
    JsonNode obj = new ObjectMapper().readTree(json);
    List<JsonNode> objects = StreamSupport
      .stream(obj.get("objects").spliterator(), false)
      .collect(Collectors.toList());

    assertEquals(3, objects.size(), "The 'objects' list should contain 3 elements");

    JsonNode firstObject = objects.get(0);
    assertEquals("One", firstObject.asText(), "The first element should be One");
}

This approach is useful when we want to leverage Java Streams for a concise and expressive way to extract and process elements from a JSON array.

6. Using Iterator

An Iterator is one of many ways we can traverse a collection. In this approach, we utilized an iterator to traverse the elements of the objects array in the given JSON structure:

@Test
void givenJsonNode_whenUsingIterator_thenConvertToArrayNode() throws Exception {
    String json = "{\"objects\": [\"One\", \"Two\", \"Three\"]}";
    JsonNode datasets = new ObjectMapper().readTree(json);
    Iterator<JsonNode> iterator = datasets.withArray("objects").elements();

    int count = 0;
    while (iterator.hasNext()) {
        JsonNode dataset = iterator.next();
        System.out.print(dataset.toString() + " ");
        count++;
    }
    assertEquals(3, count, "The 'objects' list should contain 3 elements");
}

This approach reduces the overall complexity by directly iterating through the elements. It provides a straightforward mechanism for customizing the processing of JSON elements during iteration.

7. Conclusion

In this tutorial, we explored various approaches to simplifying array operations on JsonNode without explicitly typecasting it to ArrayNode in Jackson.

As always, the source code is available over on GitHub.

Course – LS (cat=JSON/Jackson)

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE
res – Jackson (eBook) (cat=Jackson)
Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.