Java JSON Processing with Jackson Examples

Parse JSON trees, serialize Java records and validate field types while separating malformed JSON from invalid application data.

Lesson 75 of 127Intermediate13 min read

JSON processing in Java means reading a JSON document into usable values or writing Java data as JSON. JSON supports objects, arrays, strings, numbers, booleans and null. It does not include Java class definitions, constructors or methods.

The standard Java 17 library does not provide a general JSON object mapper. These examples use Jackson 2.19.2 as a stated dependency baseline. ObjectMapper can parse a document into a JsonNode tree, bind it to a Java record, or produce properly escaped JSON from an object. The version is pinned for reproducibility, rather than described as the latest release.

Set up the dependency before copying code

Jackson databind depends on its core and annotations libraries. Maven resolves these transitive dependencies when you declare jackson-databind. An import alone does not download any of them.

Save this complete dependency configuration as pom.xml in a new practice directory:

XML
<project xmlns="http://maven.apache.org/POM/4.0.0">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.example</groupId>
  <artifactId>json-practice</artifactId>
  <version>1.0</version>
  <dependencies>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.19.2</version>
    </dependency>
  </dependencies>
</project>

Retrieve the declared dependency JARs, then compile and run an example. On Windows:

SHELL
mvn org.apache.maven.plugins:maven-dependency-plugin:3.8.1:copy-dependencies
javac -cp "target/dependency/*" JsonKitReadExample.java
java -cp ".;target/dependency/*" JsonKitReadExample

On macOS or Linux, the runtime classpath uses a colon between the current directory and dependency directory. Keep the JARs available during both compilation and execution. Replace the class name when running a different example below.

JSON shape and Java types

A JSON object maps string property names to values. An array contains an ordered sequence. A number is not necessarily an integer, and a property containing the text "24" is still a string rather than a numeric value.

JsonNode lets you inspect those distinctions before conversion. get returns null for a missing property; path instead supplies a missing-node object that supports further safe navigation. Explicit JSON null is a separate node state, so missing and null can have different application meanings.

Convenient conversion methods can supply defaults or coerce values. That behavior is useful for optional display text but risky for required quantities. Validate node type, range and presence before treating a value as a domain input.

Tree access versus object binding

Tree access works well when a document is partly dynamic or when you need to inspect fields before mapping them. Record binding is convenient for a predictable data shape with named components.

Neither approach establishes every business invariant by itself. A record constructor can validate values during ordinary binding, while a service can enforce rules involving several fields. Decide whether unknown properties should be rejected or tolerated according to the API's compatibility policy.

Use a narrow expected target type. Avoid enabling broad polymorphic type handling for arbitrary input just to deserialize class names supplied by a caller. JSON should carry the agreed data contract rather than control which application classes are instantiated.

Escaping, numbers and null policies

Do not build JSON by concatenating unescaped user text between quotation marks. Quotes, backslashes and control characters require escaping. A serializer performs that work while preserving the difference between a string and a number.

For precise decimal amounts, choose BigDecimal and a documented scale policy instead of converting through double. JSON itself does not assign currency meaning or rounding rules to a numeric value.

Decide whether an absent property, explicit null and an empty String mean the same thing. A partial update may use absence to mean unchanged and null to mean remove. Treating both as a default empty value would erase that distinction.

Output encoding also matters when a document moves into a file or HTTP body. Use the protocol's expected encoding, commonly UTF-8, and keep character conversion separate from object mapping.

Boundaries and useful tests

Check valid input, missing required fields, explicit null, a wrong type, an out-of-range number and malformed syntax. For strict documents, decide whether duplicate property names should be rejected and configure the parser accordingly rather than relying on accidental last-value behavior.

Apply input-size and nesting limits suitable to external data. Do not log full documents containing credentials or personal information merely to diagnose a parser failure. Record useful context while preserving the cause.

Configure a mapper before sharing it, and avoid changing configuration concurrently while it is in use. The Jackson project documentation describes tree and binding APIs in more depth.

JSON Processing Summary

  • Declare libraries and keep them on both classpaths.
  • Separate JSON syntax, Java mapping and domain validation.
  • Validate required fields before permissive conversion.
  • Serialize text through a real JSON library.
  • Practice format boundaries in intermediate projects.

JSON Processing Examples

Each example shows the code, the output it produces and what each part does.

Example 1

Reading and validating a JSON object

Save this program as JsonKitReadExample.java.

The label access is deliberately simple. A production kit importer should also require a textual, nonblank kit property. Validation needs to cover every field used by its contract, not merely the field that participates in arithmetic.

Java
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

public class JsonKitReadExample {
    public static void main(String[] args) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        JsonNode root = mapper.readTree("{\"kit\":\"Mosaic\",\"pieces\":24}");
        JsonNode pieces = root.get("pieces");
        if (pieces == null || !pieces.isIntegralNumber()
                || !pieces.canConvertToInt() || pieces.intValue() < 0) {
            throw new IllegalArgumentException("Invalid pieces");
        }
        System.out.println(root.path("kit").asText());
        System.out.println(pieces.intValue() + 6);
    }
}
Output
Mosaic
30
Line-by-line explanation
  1. Lines 6 to 7The mapper parses one document into a tree without inventing a Java class for its shape.
  2. Lines 8 to 11The required pieces property must be an integer fitting int and must not be negative.
  3. Lines 13 to 14The label is displayed, and six spare pieces are added to the validated quantity.
Example 2

Writing a Java record as JSON

Jackson handles quotes and property formatting rather than relying on manual string assembly.

Property order in a JSON object is not a semantic requirement. The displayed order reflects this example's mapper and record. Tests comparing documents should usually compare parsed structures rather than incidental whitespace or object-property ordering.

Java
import com.fasterxml.jackson.databind.ObjectMapper;

public class JsonMaterialWriteExample {
    public record Material(String item, int quantity) {}

    public static void main(String[] args) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        Material material = new Material("Ribbon", 7);
        String json = mapper.writeValueAsString(material);
        System.out.println(json);
        Material restored = mapper.readValue(json, Material.class);
        System.out.println(restored.quantity());
    }
}
Output
{"item":"Ribbon","quantity":7}
7
Line-by-line explanation
  1. Line 4The record defines the expected property names and Java value types.
  2. Lines 8 to 10Serialization produces a document containing the record's data.
  3. Lines 11 to 12Binding that document reconstructs a record with the same quantity.
Example 3

Separating syntax errors from field errors

This validator accepts one numeric field and identifies two different invalid documents.

The String value ten is legal JSON but not the required integer. The final input has broken syntax, so parsing fails before field validation. Keeping those categories separate helps callers correct the actual problem.

Java
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

public class JsonValidationExample {
    public static void main(String[] args) throws Exception {
        ObjectMapper mapper = new ObjectMapper()
                .enable(DeserializationFeature.FAIL_ON_TRAILING_TOKENS);
        String[] inputs = {
                "{\"pieces\":10}", "{\"pieces\":\"ten\"}", "{\"pieces\":}"};
        for (String json : inputs) {
            try {
                JsonNode root = mapper.readTree(json);
                JsonNode value = root == null ? null : root.get("pieces");
                if (root == null || !root.isObject() || value == null || !value.isIntegralNumber()
                        || !value.canConvertToInt() || value.intValue() < 0) {
                    throw new IllegalArgumentException("Invalid pieces");
                }
                System.out.println("Accepted " + value.intValue());
            } catch (JsonProcessingException error) {
                System.out.println("Malformed JSON");
            } catch (IllegalArgumentException error) {
                System.out.println(error.getMessage());
            }
        }
    }
}
Output
Accepted 10
Invalid pieces
Malformed JSON
Line-by-line explanation
  1. Lines 8 to 9The mapper rejects additional trailing tokens beyond the expected document.
  2. Lines 14 to 18Parsing supplies a tree; the subsequent check enforces the application's field contract.
  3. Lines 21 to 24Malformed syntax and well-formed but invalid data receive different explanations.

JSON Processing FAQ

Is ObjectMapper part of the JDK?

No. It belongs to Jackson databind and needs the declared dependency.

Can I process a JSON array of records?

Yes. Specify an appropriate collection or array target type and validate each element's contract. Do not assume an object-only example accepts every JSON shape.

Which JSON library should I use in Java?

Jackson is the most widely used and is built into Spring Boot. Gson, from Google, is smaller and simple to start with. Jakarta JSON-B and JSON-P are standard APIs with several implementations. All of them read and write the same JSON, so choose the one your framework already uses.

How do I ignore JSON fields my class doesn't have?

By default Jackson fails on unknown properties. Annotate the class with @JsonIgnoreProperties(ignoreUnknown = true), or configure the mapper with disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES). Ignoring extra fields helps when an API adds new fields that your program doesn't need yet.

How do I pretty-print JSON with Jackson?

Use mapper.writerWithDefaultPrettyPrinter().writeValueAsString(value), which adds line breaks and indentation. Keep compact output for data sent between programs, where the extra whitespace only adds size.

JSON Processing Exercises

Answer each one and check it instantly. If you get stuck, open the hint before the answer.

Multiple choiceeasy

Which JSON value has a numeric type?

Predict the outputmedium

What category describes {"pieces":"ten"} under the shown validator?

JSON Processing Quiz

2 questions to check what you learned.

  1. Why use writeValueAsString instead of concatenating quoted user text?

    • It escapes text and preserves JSON value types
    • It removes every property
    • It makes all Java classes safe to instantiate
  2. What should a semantic JSON round-trip test compare?

    • The meaningful parsed values
    • Only whitespace and property order
    • Only the number of source lines