Jackson Library
JSON Parsing
JsonNode
Programming
Java

How to parse a JSON string into JsonNode in Jackson?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

When you do not want to bind JSON directly to a Java class, Jackson's tree model is a good alternative. JsonNode lets you parse JSON into a navigable object structure and inspect only the fields you care about.

The usual entry point is ObjectMapper.readTree. It turns a JSON string into a JsonNode that can represent an object, array, string, number, boolean, or null.

Parsing a JSON String with readTree

Here is the standard pattern:

java
1import com.fasterxml.jackson.databind.JsonNode;
2import com.fasterxml.jackson.databind.ObjectMapper;
3
4public class Main {
5    public static void main(String[] args) throws Exception {
6        String json = """
7            {
8              "name": "Alice",
9              "age": 30,
10              "roles": ["admin", "editor"]
11            }
12            """;
13
14        ObjectMapper mapper = new ObjectMapper();
15        JsonNode root = mapper.readTree(json);
16
17        System.out.println(root.get("name").asText());
18        System.out.println(root.get("age").asInt());
19        System.out.println(root.get("roles").get(0).asText());
20    }
21}
text
Alice
30
admin

readTree is convenient because you do not need a DTO class up front. That makes it useful for ad hoc parsing, dynamic payloads, or tests where only a few fields matter.

get Versus path

One of the first practical choices is whether to use get or path.

  • 'get("field") returns null if the field is missing'
  • 'path("field") returns a special missing node instead of null'

That difference matters for defensive code:

java
1JsonNode root = mapper.readTree("{\"name\":\"Alice\"}");
2
3System.out.println(root.path("name").asText());
4System.out.println(root.path("email").asText("[email protected]"));

Using path often leads to safer traversal because you can keep chaining calls without immediate NullPointerException risk.

If you need to distinguish between "missing" and "present but null," check explicitly with methods such as isMissingNode() and isNull().

When JsonNode Is a Better Choice Than a POJO

Tree parsing is especially useful when:

  • the JSON schema changes often
  • you only need a few fields from a large payload
  • the structure is partially unknown at compile time
  • you are writing tooling, validation, or debugging code

If the structure is stable and maps cleanly to domain classes, binding directly to a POJO is usually more maintainable. But for flexible inspection, JsonNode is hard to beat.

It is also common to mix approaches. You might inspect a top-level JsonNode first, then convert one nested sub-tree into a typed object once you know which branch you are dealing with.

Handling Invalid JSON

readTree throws an exception when the input is not valid JSON, so malformed payloads need normal exception handling:

java
1try {
2    JsonNode root = mapper.readTree("{bad json}");
3    System.out.println(root);
4} catch (Exception ex) {
5    System.err.println("Invalid JSON: " + ex.getMessage());
6}

In production code, it is also a good idea to reuse a configured ObjectMapper rather than creating a new one for every parse. ObjectMapper is designed to be reused.

Iterating Arrays and Nested Objects

Once you have a JsonNode, you can walk arrays and nested objects without creating extra model classes:

java
1JsonNode root = mapper.readTree("{\"items\":[{\"id\":1},{\"id\":2}]}");
2
3for (JsonNode item : root.path("items")) {
4    System.out.println(item.path("id").asInt());
5}

This is one of the biggest advantages of the tree model. You can inspect variable structures incrementally and decide later whether a sub-tree should stay dynamic or be converted into a typed Java object.

Common Pitfalls

  • Calling get() on a missing field and then dereferencing null.
  • Using asText() or asInt() without thinking about default values for missing or mismatched nodes.
  • Recreating ObjectMapper repeatedly instead of reusing one configured instance.
  • Using JsonNode for large, stable payloads where strongly typed binding would be clearer.

Summary

  • Parse a JSON string into JsonNode with ObjectMapper.readTree.
  • Use JsonNode when the payload is dynamic or you only need selected fields.
  • Prefer path() over get() when you want safer traversal of optional fields.
  • Handle malformed JSON with normal exception handling.
  • Reuse your ObjectMapper and choose typed binding when the schema is stable.

Course illustration
Course illustration

All Rights Reserved.