Why Reusing a Single Jackson ObjectMapper Boosts JSON Performance 10×

This article explains how repeatedly creating Jackson ObjectMapper instances hurts performance, demonstrates a JMH benchmark comparing new, singleton, and ThreadLocal ObjectMapper usages, and concludes that a single globally shared ObjectMapper can achieve up to ten times faster JSON parsing.

macrozheng
macrozheng
macrozheng
Why Reusing a Single Jackson ObjectMapper Boosts JSON Performance 10×

Background

Since the frequent security issues of fastjson, Jackson has become the default JSON library in the Spring ecosystem, but many developers notice that it lacks a simple JSON.parseObject -style method and requires creating an ObjectMapper instance for each conversion.

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

This pattern appears widely in CV engineering code and raises the question of whether repeatedly instantiating ObjectMapper hurts performance.

Is the Code Problematic?

Although the code works, creating a new ObjectMapper on every call wastes memory and may impact speed. ObjectMapper is thread‑safe and can be shared as a singleton.

Benchmark with JMH

To answer the performance question we use JMH (Java Microbenchmark Harness), a high‑precision benchmarking tool that can measure operations at the nanosecond level.

@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 {
        Map map = state.GLOBAL_MAP.readValue(json, Map.class);
        return map;
    }

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

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

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

Benchmark results:

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

The single global ObjectMapper processes about 20 million JSON parses per second, roughly ten times faster than creating a new instance each time. Using a ThreadLocal gives a modest improvement but not a dramatic one.

Conclusion

For typical projects you should keep one globally shared ObjectMapper. It is thread‑safe, reduces memory churn, and delivers an order‑of‑magnitude performance gain. Separate instances are only justified when you need distinct configuration for different use cases.

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.

JavaperformanceBenchmarkJacksonJMHObjectMapper
macrozheng
Written by

macrozheng

Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.

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.