Jackson ObjectMapper: The Complete Guide to Reading and Writing JSON in Java

Jackson is the most widely used JSON library in the Java ecosystem, and ObjectMapper is its workhorse. Whether you need to convert a Java object into a JSON string, parse a JSON file from disk, or read from an HTTP response body, ObjectMapper handles it all with a clean, consistent API. This guide covers everything you need to use Jackson’s ObjectMapper effectively in real projects.

What Is Jackson ObjectMapper?

ObjectMapper is the central class in Jackson’s data-binding API. It bridges the gap between Java objects (POJOs) and JSON text. Internally it uses a JsonParser for reading and a JsonGenerator for writing, but you rarely interact with those directly — ObjectMapper wraps them behind a higher-level API.

Three key facts to keep in mind:

  • Thread-safe after configuration. Create one instance, share it across your application. Recreating it per request is expensive.
  • Highly configurable. Date formats, null handling, unknown-property behaviour, and much more are controlled via feature flags.
  • Extensible. Custom serialisers, deserialisers, and modules let you handle any type Jackson does not know about out of the box.

Adding Jackson to Your Project

The jackson-databind artifact is all you need. It pulls in jackson-core and jackson-annotations as transitive dependencies.

Maven (pom.xml):

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>3.1.2</version>
</dependency>

Gradle (build.gradle):

implementation 'com.fasterxml.jackson.core:jackson-databind:3.1.2'

If you are using Spring Boot, Jackson is already on the classpath via spring-boot-starter-web — no explicit declaration needed.

Serialising Java Objects to JSON

Serialisation converts a Java object into JSON. Consider this POJO:

public class Article {
    private Long         articleId;
    private String       title;
    private List<String> tags;
    // Constructors, getters, and setters
}

Write to a String:

ObjectMapper mapper = new ObjectMapper();

Article article = new Article(1L, "Jackson Deep Dive", List.of("java", "json"));
String jsonOutput = mapper.writeValueAsString(article);

System.out.println(jsonOutput);
// Output: {"articleId":1,"title":"Jackson Deep Dive","tags":["java","json"]}

Write to a File:

mapper.writeValue(new File("article.json"), article);
// Creates article.json on disk

Pretty-printed output:

String prettyJson = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(article);
/*
{
  "articleId" : 1,
  "title" : "Jackson Deep Dive",
  "tags" : [ "java", "json" ]
}
*/

Deserialising JSON to Java Objects

Deserialisation converts JSON back into a Java object. Use readValue() and pass the target class as the second argument.

Read from a String:

String json = "{"articleId":1,"title":"Jackson Deep Dive","tags":["java","json"]}";
Article article = mapper.readValue(json, Article.class);

System.out.println(article.getTitle()); // Output: Jackson Deep Dive

Read from a File:

Article article = mapper.readValue(new File("article.json"), Article.class);
System.out.println(article.getArticleId()); // Output: 1

Read from a URL:

Article article = mapper.readValue(
    new URL("https://api.example.com/articles/1"),
    Article.class
);

Working with Collections and Generic Types

For generic types like List<Article>, you cannot pass List.class directly because Java erases the type parameter at runtime. Use TypeReference instead to preserve the full generic type information Jackson needs to instantiate the correct parameterised collection.

String jsonArray = "[{"articleId":1,"title":"First"},{"articleId":2,"title":"Second"}]";

List<Article> articles = mapper.readValue(
    jsonArray,
    new TypeReference<List<Article>>() {}
);

System.out.println(articles.size()); // Output: 2

How the Code Works

  1. ObjectMapper is created once and reused. Jackson scans your POJO’s getters and fields to build an internal serialisation/deserialisation model the first time a type is encountered, then caches it.
  2. writeValueAsString() calls the internal JsonSerializer chain, writing each property to an in-memory buffer, then returns the completed JSON string.
  3. readValue() tokenises the JSON input via JsonParser, then maps each token to the corresponding field on your POJO using the cached model.
  4. TypeReference captures the full generic type at compile time (via an anonymous subclass), giving Jackson the information it needs to instantiate the correct parameterised type at runtime.

Essential ObjectMapper Configuration Options

Raw ObjectMapper defaults are strict. Most real projects need at least a few of these tweaks:

ObjectMapper mapper = new ObjectMapper()
    // Do not fail when JSON has fields your POJO does not declare
    .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
    // Serialise Java 8 dates correctly (requires jackson-datatype-jsr310)
    .registerModule(new JavaTimeModule())
    // Write dates as ISO-8601 strings, not numeric timestamps
    .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
    // Skip null fields during serialisation
    .setSerializationInclusion(JsonInclude.Include.NON_NULL);

Sample Output

Given an Article object with articleId=1, title="Jackson Deep Dive", tags=["java","json"], and a null author field, the mapper configured with NON_NULL produces:

{"articleId":1,"title":"Jackson Deep Dive","tags":["java","json"]}

The author field is absent because it was null and the mapper was told to skip nulls. Without that setting, the output would include "author":null.

See Also

AI Prompts for Jackson ObjectMapper

Generate POJO Round-Trip Code

I have this POJO class: [paste your class here]. I am using Jackson 3.1.2. Generate five working examples using JsonMapper.builder().build(): serialise an instance to a String, serialise to a File, serialise to an OutputStream, deserialise from a String, and deserialise from an InputStream. For any LocalDate or Optional fields, confirm no extra modules are needed. Include a sample JSON output comment after each serialise call.

What it does: Produces five copy-paste-ready snippets covering all common I/O variants for the exact class provided. Includes sample JSON output as inline comments so you can verify the mapping is correct without running the code first.

When to use it: When adding a new DTO to a Jackson 3 project and wanting verified, runnable code for every I/O operation before writing tests. Also useful when onboarding teammates who are new to Jackson’s API and need concrete examples rather than documentation links.

Configure REST Client Mapper

I am writing a typed REST client in Java using Jackson 3.1.2 that calls a third-party API. Configure a JsonMapper using the builder pattern with these requirements: unknown fields must not throw an exception, dates must serialise as ISO-8601 strings not epoch milliseconds, null fields must be excluded from outbound request bodies, and single-quoted JSON must be accepted if the target API is lenient. Add a one-line comment on every builder call explaining the exact runtime effect of that setting.

What it does: Generates a fully commented JsonMapper.builder() block tailored to REST client usage, with each setting explained in plain English immediately below it. The output is suitable for pasting directly into a @Configuration class or a client unit test fixture.

When to use it: When writing a client against an external API that may evolve its schema, returns ISO-8601 dates, and where you want clean, minimal outbound payloads. Especially valuable when the API documentation is incomplete and you need the mapper to be tolerant of unexpected fields without masking genuine deserialisation errors.

Deserialise Generic Collections

Using Jackson 3.1.2, show me how to deserialise these four JSON structures into typed Java collections: a JSON array into List<OrderDto>, a JSON object into Map<String, OrderDto>, a paginated wrapper like {“content”:[…],”totalElements”:100} into a generic Page<OrderDto> class, and an array of unknown objects into List<Map<String, Object>>. Explain why TypeReference is required for each case and what goes wrong if you pass List.class directly.

What it does: Provides four complete examples with working TypeReference instantiation patterns for each collection shape, explains Java type erasure and why List.class produces an untyped List<LinkedHashMap> instead of the expected typed list, and shows the generic page wrapper pattern common in Spring Data REST responses.

When to use it: When consuming paginated REST APIs, batch endpoints returning JSON arrays, or any response whose root element is a collection or generic wrapper. Run this prompt when readValue(json, List.class) compiles but produces ClassCastException at runtime when you try to use the list elements.

Conclusion

ObjectMapper is the foundation of all Jackson-based JSON handling in Java. Understanding how to create it correctly (once, thread-safe, properly configured), how to serialise and deserialise both simple objects and generic collections, and which configuration flags matter most will take you through the vast majority of real-world JSON tasks. The subsequent parts of this series build on this foundation to cover annotations, custom serialisers, polymorphism, streaming performance, and security.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.