Why Reusing a Single Jackson ObjectMapper Boosts JSON Parsing Speed 10×

Using Jackson's ObjectMapper for JSON parsing, this article benchmarks three approaches—creating a new mapper per call, sharing a global singleton, and using ThreadLocal—revealing that a single shared ObjectMapper can achieve up to ten times higher throughput, while ThreadLocal offers only modest gains.

Java Backend Technology
Java Backend Technology
Java Backend Technology
Why Reusing a Single Jackson ObjectMapper Boosts JSON Parsing Speed 10×

Background

After frequent security issues with fastjson, Jackson has become the default JSON processor in the Spring ecosystem, leading to widespread adoption.

Typical usage

Unlike fastjson’s JSON.parseObject, Jackson requires creating an ObjectMapper instance to perform parsing, as shown below.

public String getCarString(Car car) {
    ObjectMapper objectMapper = new ObjectMapper();
    String str = objectMapper.writeValueAsString(car);
    return str;
}

Although this code works, creating a new mapper for every call can waste memory and affect performance.

Thread‑safety of ObjectMapper

ObjectMapper is thread‑safe, so a single instance can be shared across threads without issues.

Benchmarking with JMH

To measure the impact of different instantiation strategies, the Java Microbenchmark Harness (JMH) is used. Three scenarios are benchmarked:

Instantiate a new ObjectMapper inside the method.

Use a globally shared singleton ObjectMapper.

Assign an ObjectMapper to each thread via ThreadLocal.

The benchmark class is shown below.

@BenchmarkMode({Mode.Throughput})
@OutputTimeUnit(TimeUnit.SECONDS)
@State(Scope.Thread)
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Fork(1)
@Threads(10)
public class ObjectMapperTest {
    String json = "{ \"color\" : \"Black\", \"type\" : \"BMW\" }";

    @State(Scope.Benchmark)
    public static class BenchmarkState {
        ObjectMapper GLOBAL_MAP = new ObjectMapper();
        ThreadLocal<ObjectMapper> GLOBAL_MAP_THREAD = new ThreadLocal<>();
    }

    @Benchmark
    public Map globalTest(BenchmarkState state) throws Exception {
        return state.GLOBAL_MAP.readValue(json, Map.class);
    }

    @Benchmark
    public Map globalTestThreadLocal(BenchmarkState state) throws Exception {
        if (state.GLOBAL_MAP_THREAD.get() == null) {
            state.GLOBAL_MAP_THREAD.set(new ObjectMapper());
        }
        return state.GLOBAL_MAP_THREAD.get().readValue(json, Map.class);
    }

    @Benchmark
    public Map localTest() throws Exception {
        ObjectMapper objectMapper = new ObjectMapper();
        return objectMapper.readValue(json, Map.class);
    }

    public static void main(String[] args) throws Exception {
        Options opts = new OptionsBuilder()
                .include(ObjectMapperTest.class.getSimpleName())
                .resultFormat(ResultFormatType.CSV)
                .build();
        new Runner(opts).run();
    }
}

An illustration of a typical JMH execution flow:

JMH execution diagram
JMH execution diagram

The benchmark results are:

Benchmark                         Mode  Cnt          Score          Error  Units
ObjectMapperTest.globalTest       thrpt    5  25125094.559 ± 1754308.010  ops/s
ObjectMapperTest.globalTestThreadLocal thrpt    5  31780573.549 ± 7779240.155  ops/s
ObjectMapperTest.localTest       thrpt    5   2131394.345 ±  216974.682  ops/s

Findings

Creating a new ObjectMapper for each call yields about 2 million operations per second, while reusing a single global instance reaches roughly 20 million ops/s—a ten‑fold improvement. ThreadLocal provides a modest increase over the global singleton but not a dramatic one.

Conclusion

Because ObjectMapper is thread‑safe, projects should maintain a single shared instance (or a few configured instances) rather than instantiate it repeatedly. This practice improves performance and promotes cleaner code.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaJSONJacksonJMHObjectMapper
Java Backend Technology
Written by

Java Backend Technology

Focus on Java-related technologies: SSM, Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading. Occasionally cover DevOps tools like Jenkins, Nexus, Docker, and ELK. Also share technical insights from time to time, committed to Java full-stack development!

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.