Back to Blog
spring-bootjacksonobjectmapperperformancejavabest-practices

Why Creating ObjectMapper in Every Method Destroys Your Spring Boot Performance (2026)

Instantiating ObjectMapper on every call is one of the most common Java performance mistakes. Learn why it's expensive, how to detect it, and the correct singleton pattern.

J

JOptimize Team

May 20, 2026· 6 min read

Creating a new ObjectMapper() inside a method is one of the most widespread - and most costly - performance anti-patterns in Java. ObjectMapper initialization is expensive: it scans classpath modules, registers serializers, and builds internal caches. Do it on every request and you're wasting CPU on setup work that should happen exactly once.


The Anti-Pattern: ObjectMapper as a Local Variable

// ANTI-PATTERN - seen constantly in production codebases @Service public class UserService { public String serializeUser(User user) throws JsonProcessingException { ObjectMapper mapper = new ObjectMapper(); // Created on EVERY call return mapper.writeValueAsString(user); } public User deserializeUser(String json) throws JsonProcessingException { ObjectMapper mapper = new ObjectMapper(); // Again! return mapper.readValue(json, User.class); } }

At 100 requests/second, this creates 100+ ObjectMapper instances per second. Each one rebuilds the entire Jackson module registry, registers default serializers, and allocates significant heap space. This:

  • Wastes CPU on redundant initialization
  • Creates GC pressure from short-lived heavy objects
  • Prevents Jackson from using its internal per-instance caching

Why ObjectMapper Is Expensive to Create

ObjectMapper initialization does non-trivial work:

  1. Module discovery - scans the classpath for jackson-modules via ServiceLoader
  2. Serializer/deserializer cache - builds a TypeFactory and registers all default (de)serializers
  3. Feature flags - processes all default SerializationFeature and DeserializationFeature settings
  4. Date/time support - registers JavaTimeModule if on the classpath

A quick benchmark shows ObjectMapper instantiation takes ~2-5ms on a warm JVM. At 500 RPS with two JSON operations per request, that's 2-5 seconds of pure overhead per second - just from mapper creation.


The Fix: ObjectMapper Is Thread-Safe - Use It as a Singleton

ObjectMapper is thread-safe for read operations after configuration. The correct pattern is one instance per application:

Option 1: Inject Spring Boot's auto-configured ObjectMapper

Spring Boot auto-configures an ObjectMapper bean with all the right settings (JavaTimeModule, etc.). Just inject it:

@Service @RequiredArgsConstructor public class UserService { private final ObjectMapper objectMapper; // Spring-managed singleton ? public String serializeUser(User user) throws JsonProcessingException { return objectMapper.writeValueAsString(user); } public User deserializeUser(String json) throws JsonProcessingException { return objectMapper.readValue(json, User.class); } }

This is the simplest and recommended approach for Spring Boot applications.

Option 2: Declare your own @Bean

If you need custom configuration:

@Configuration public class JacksonConfig { @Bean @Primary public ObjectMapper objectMapper() { return JsonMapper.builder() .addModule(new JavaTimeModule()) .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) .enable(MapperFeature.DEFAULT_VIEW_INCLUSION) .build(); } }

Option 3: Static singleton for non-Spring code

public final class JsonUtils { private static final ObjectMapper MAPPER = JsonMapper.builder() .addModule(new JavaTimeModule()) .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) .build(); private JsonUtils() {} public static String toJson(Object obj) throws JsonProcessingException { return MAPPER.writeValueAsString(obj); } public static <T> T fromJson(String json, Class<T> type) throws JsonProcessingException { return MAPPER.readValue(json, type); } }

What About Thread Safety?

ObjectMapper is safe to share across threads as long as you don't reconfigure it after initialization. The rule:

// SAFE - reading/writing JSON concurrently String json1 = mapper.writeValueAsString(obj1); // thread 1 String json2 = mapper.writeValueAsString(obj2); // thread 2 (concurrent) ? // UNSAFE - modifying configuration after construction mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); // in a request handler ?

If you need per-request configuration, use ObjectWriter or ObjectReader (which are immutable and thread-safe):

// Thread-safe per-view serialization ObjectWriter writer = objectMapper.writerWithView(UserViews.Public.class); String json = writer.writeValueAsString(user); // ?

Common Mistakes to Avoid

  • new ObjectMapper() in a @Bean method without @Bean scope control - if the method is called multiple times, you get multiple instances; always annotate with @Bean
  • Calling mapper.configure() after the bean is shared - this modifies global state and causes race conditions; configure in the constructor or builder only
  • Using ObjectMapper for String ? Map conversions repeatedly - consider TypeReference caching: private static final TypeReference<Map<String, Object>> MAP_TYPE = new TypeReference<>() {}
  • Ignoring JsonProcessingException - wrapping it in a generic RuntimeException loses context; use a proper error handler or @ControllerAdvice

Summary

ObjectMapper is expensive to create and safe to share - always use it as a singleton. In Spring Boot, simply inject the auto-configured ObjectMapper bean. If you need custom config, declare a @Bean. Never instantiate it inside a method or per-request. This one change can eliminate significant CPU and GC overhead in JSON-heavy services.


Detect ObjectMapper Anti-Patterns Automatically

JOptimize scans your codebase for new ObjectMapper() inside methods and service classes, flagging every instance with a suggested refactoring to inject the singleton.

Eliminate unnecessary ObjectMapper instantiation and reduce CPU overhead - free scan, no configuration required.

Want to go deeper?

Master Spring Boot, security, and Java performance with hands-on courses.

Detect issues in your project

JOptimize finds N+1 queries, EAGER collections, and 70+ other issues in your Java codebase — in under 30 seconds.