Should I declare Jackson's ObjectMapper as a static field?

JavaJsonJackson

Java Problem Overview


The Jackson library's ObjectMapper class seems to be thread safe.

Does this mean that I should declare my ObjectMapper as a static field like this

class Me {
    private static final ObjectMapper mapper = new ObjectMapper();
}

instead of as an instance-level field like this?

class Me {
    private final ObjectMapper mapper = new ObjectMapper();
}

Java Solutions


Solution 1 - Java

Yes, that is safe and recommended.

The only caveat from the page you referred is that you can't be modifying configuration of the mapper once it is shared; but you are not changing configuration so that is fine. If you did need to change configuration, you would do that from the static block and it would be fine as well.

EDIT: (2013/10)

With 2.0 and above, above can be augmented by noting that there is an even better way: use ObjectWriter and ObjectReader objects, which can be constructed by ObjectMapper. They are fully immutable, thread-safe, meaning that it is not even theoretically possible to cause thread-safety issues (which can occur with ObjectMapper if code tries to re-configure instance).

Solution 2 - Java

Although ObjectMapper is thread safe, I would strongly discourage from declaring it as a static variable, especially in multithreaded application. Not even because it is a bad practice, but because you are running a heavy risk of deadlocking. I am telling it from my own experience. I created an application with 4 identical threads that were getting and processing JSON data from web services. My application was frequently stalling on the following command, according to the thread dump:

Map aPage = mapper.readValue(reader, Map.class);

Beside that, performance was not good. When I replaced static variable with the instance based variable, stalling disappeared and performance quadrupled. I.e. 2.4 millions JSON documents were processed in 40min.56sec., instead of 2.5 hours previously.

Solution 3 - Java

A trick I learned from this PR if you don't want to define it as a static final variable but want to save a bit of overhead and guarantee thread safe.

private static final ThreadLocal<ObjectMapper> om = new ThreadLocal<ObjectMapper>() {
    @Override
    protected ObjectMapper initialValue() {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        return objectMapper;
    }
};

public static ObjectMapper getObjectMapper() {
    return om.get();
}

credit to the author.

Solution 4 - Java

Although it is safe to declare a static ObjectMapper in terms of thread safety, you should be aware that constructing static Object variables in Java is considered bad practice. For more details, see https://stackoverflow.com/questions/7026507 (and if you'd like, my answer)

In short, statics should be avoided because the make it difficult to write concise unit tests. For example, with a static final ObjectMapper, you can't swap out the JSON serialization for dummy code or a no-op.

In addition, a static final prevents you from ever reconfiguring ObjectMapper at runtime. You might not envision a reason for that now, but if you lock yourself into a static final pattern, nothing short of tearing down the classloader will let you re-initialize it.

In the case of ObjectMapper its fine, but in general it is bad practice and there is no advantage over using a singleton pattern or inversion-of-control to manage your long-lived objects.

Solution 5 - Java

com.fasterxml.jackson.databind.type.TypeFactory._hashMapSuperInterfaceChain(HierarchicType)

com.fasterxml.jackson.databind.type.TypeFactory._findSuperInterfaceChain(Type, Class)
  com.fasterxml.jackson.databind.type.TypeFactory._findSuperTypeChain(Class, Class)
     com.fasterxml.jackson.databind.type.TypeFactory.findTypeParameters(Class, Class, TypeBindings)
        com.fasterxml.jackson.databind.type.TypeFactory.findTypeParameters(JavaType, Class)
           com.fasterxml.jackson.databind.type.TypeFactory._fromParamType(ParameterizedType, TypeBindings)
              com.fasterxml.jackson.databind.type.TypeFactory._constructType(Type, TypeBindings)
                 com.fasterxml.jackson.databind.type.TypeFactory.constructType(TypeReference)
                    com.fasterxml.jackson.databind.ObjectMapper.convertValue(Object, TypeReference)

The method _hashMapSuperInterfaceChain in class com.fasterxml.jackson.databind.type.TypeFactory is synchronized. Am seeing contention on the same at high loads.

May be another reason to avoid a static ObjectMapper

Solution 6 - Java

This question may be old, but here's what I do.

Hold the ObjectMapper instance in a thread-safe singleton:

public final class JacksonObjectMapperHolder {

  private static volatile JacksonObjectMapperHolder INSTANCE;

  private static final Object MUTEX = new Object();

  public static JacksonObjectMapperHolder getInstance() {
    JacksonObjectMapperHolder instance = INSTANCE;

    if(instance == null) {
      synchronized(MUTEX) {
        instance = INSTANCE;

        if(instance == null) {
          INSTANCE = instance = new JacksonObjectMapperHolder();
        }
      }
    }

    return instance;
  }

  private final ObjectMapper objectMapper = new ObjectMapper();

  private JacksonObjectMapperHolder() {
    super();
  }

  public final ObjectMapper getObjectMapper() {
    return objectMapper;
  }

}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionCheok Yan ChengView Question on Stackoverflow
Solution 1 - JavaStaxManView Answer on Stackoverflow
Solution 2 - JavaGary GreenbergView Answer on Stackoverflow
Solution 3 - JavaLin_nView Answer on Stackoverflow
Solution 4 - JavaJBCPView Answer on Stackoverflow
Solution 5 - JavaHarshitView Answer on Stackoverflow
Solution 6 - JavaOliverView Answer on Stackoverflow