463

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();
}
Lim
  • 753
  • 14
  • 31
Cheok Yan Cheng
  • 47,586
  • 132
  • 466
  • 875

6 Answers6

623

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).

Guido
  • 46,642
  • 28
  • 120
  • 174
StaxMan
  • 113,358
  • 34
  • 211
  • 239
  • Do you have any reference source? – Cheok Yan Cheng Oct 12 '10 at 20:11
  • 37
    @StaxMan: I am a bit concerned if `ObjectMapper` is still thread-safe after [`ObjectMapper#setDateFormat()`](http://jackson.codehaus.org/1.9.0/javadoc/org/codehaus/jackson/map/ObjectMapper.html#setDateFormat%28java.text.DateFormat%29) is called. It is known that [`SimpleDateFormat` is not thread safe](http://stackoverflow.com/questions/6840803), thus `ObjectMapper` won't be unless it clones e.g. `SerializationConfig` before each `writeValue()` (I doubt). Could you debunk my fear? – dma_k Aug 02 '13 at 12:09
  • 67
    `DateFormat` is indeed cloned under the hood. Good suspicion there, but you are covered. :) – StaxMan Aug 02 '13 at 19:43
  • 1
    Thanks, I have found the code that clones in `DateBasedDeserializer` / `DateTimeSerializerBase`. – dma_k Aug 06 '13 at 13:24
  • 3
    I've faced strange behaviors during unit/integration tests of a large enterprise application. When putting ObjectMapper as static final class attribute I started facing PermGen issues. Would anyone care to explain probable causes? I was using jackson-databind version 2.4.1. – Alejo Ceballos Aug 17 '15 at 16:01
  • 1
    @AlejoCeballos my guess would be that you might be parsing documents with "random" (arbitrary, unbounded set) of property names; like UUIDs or numeric ids. If so, canonicalization could become problematic -- however, should not actually matter regarding use of static mapper. – StaxMan Aug 17 '15 at 20:31
  • 1
    Just to add a hint for the date mapping: Jackson does not seem to use the standard ISO format of `"yyyy-MM-dd'T'HH:mm:ss.SSSXXX`. If we have to replace the date mapper like me all the time, do not forgot to implement the clone method. I think I had some threading problems if not doing so. – k_o_ Dec 28 '15 at 23:54
  • 1
    Hi StaxMan, would you help how can be constructed ObjectWriter and ObjectReader from ObjectMapper? I have not found a way using jackson library 2.7.3. Thx in advance. – Miklos Krivan Apr 30 '16 at 09:52
  • 2
    @MiklosKrivan have you looked at `ObjectMapper` at all?! Methods are named `writer()` and `reader()` (and some `readerFor()`, `writerFor()`). – StaxMan May 03 '16 at 06:13
  • Sorry @StaxMan you are absolutely right it was my fault that I am missed it. Thx for your feedback. – Miklos Krivan May 03 '16 at 16:20
  • 1
    When you say "that you can't be modifying configuration of the mapper once it is shared" do you mean that jackson throws an exception if it is done or that I have to be careful there? I.e. is the instance cloned on every "mapper.with()" call? I read somewhere that this is the recommended way e.g. for request based decisions like pretty printing the json. – Karussell May 23 '17 at 15:58
  • 2
    There is no `mapper.with()` call (since "with" in Jackson implies construction of a new instance, and thread-safe execution). But regarding config changes: no checking is made, so config access to `ObjectMapper` must be guarded. As to "copy()": yes, that creates a fresh new copy that may be fully (re)configured, according to same rules: fully configure it first, then use, and that is fine. There is non-trivial cost associated (since copy can not use any of cached handlers), but it is the safe way, yes. – StaxMan Jun 02 '17 at 18:30
  • 2
    ... and as to "why not see if someone tries to reconfig": that would require additional state-keeping, synchronization. For Jackson 3.x it may make sense to use builder-pattern, make `ObjectMapper` immutable similar to `ObjectReader`/`ObjectWriter`: but that's major API change so can't be done with 2.x. Another way to protect against reconfig is to only expose `ObjectReader`s and `ObjectWriter`s; keep access to mapper only available to small part of system. – StaxMan Jun 02 '17 at 18:33
  • @StaxMan - Is it ok to instantiate an object mapper inside the toString() method of a class ? Does it depend on how many times toString() is called ? – MasterJoe Nov 10 '19 at 03:03
  • 1
    @MasterJoe2 given that construction of ObjectMapper is a rather heavy-weight operation, answer depends: yes, it is safe and functionally correct to do that. But it is is also extremely inefficient to do it. – StaxMan Nov 10 '19 at 23:58
  • @StaxMan - So, would it be better to have a static object mapper for the entire class, given that I don't need to change the mapper's config after its instantiation ? After that, can I use ObjectWriter and ObjectReader instances in my toString() ? Please let me know if I should open a new question for this. thank you. – MasterJoe Nov 14 '19 at 19:47
  • 2
    @MasterJoe2 static object mapper for entire class sounds better (or even just ObjectWriter) than creating it every time `toString()` is called. Or even separate helper class with static instance, method, if there are many `toString()`s to implement across many classes? – StaxMan Nov 15 '19 at 20:21
  • Would the ObjectWriter and ObjectReader objects have internal synchronization? I mean we would not want the competing threads forces to wait for a very long time. – Awan Biru Feb 19 '21 at 16:50
  • @AwanBiru They do not have any more internal synchronization than `ObjectMapper` and in particular if root value serializer/deserializer is fetched for instance should have no contestion. Access to cached (de)serializers can still have some synchronization. – StaxMan Feb 20 '21 at 19:19
  • @StaxMan yes I just run with profiler on version 2.10.x and did not see lock or monitor captured so far. U mention of root value serializer/deserializer fetched for instance, what would that mean? – Awan Biru Feb 21 '21 at 05:38
  • 1
    @AwanBiru during serialization, deserialization, each Java type has its own kind of (de)serializer. Not all of these can be determined statically (especially for serialization; and in general always for polymorphic types), so some of secondary (de)serializers may be fetched during processing. They get cached and caching requires synchronization. For simple POJOs with scalar types no such access would be needed, for more complex type graphs yes. – StaxMan Feb 22 '21 at 17:38
  • hopefully this answer stays same for question here https://stackoverflow.com/questions/73752793/jacksons-objectmapper-with-rowmapper-in-sql @dma_k – mattsmith5 Sep 17 '22 at 07:10
87

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.

Gary Greenberg
  • 1,084
  • 8
  • 14
  • 23
    Gary's answer completely makes sense. But going with a creating an `ObjectMapper` instance for every class instance may prevent locks but can be really heavy on GC later on (imagine one ObjectMapper instance for every instance of the class you create) . A middle path approach can be, instead of keeping just one (public) static `ObjectMapper` instance across the application, you can declare a (private) **static** instance of `ObjectMapper` **in every class**. This will reduce a global lock (by distributing the load class-wise), and won't create any new object either, hence light on GC too. – Abhidemon Oct 07 '16 at 12:26
  • 1
    And of course, maintaining an `ObjectPool` is the best way you can go with - thereby giving the best `GC` and `Lock` performances. You can refer to the following link for apache-common's `ObjectPool` implementation. https://commons.apache.org/proper/commons-pool/api-1.6/org/apache/commons/pool/impl/GenericObjectPool.html – Abhidemon Mar 20 '17 at 07:53
  • 21
    I would suggest an alternative: keep static `ObjectMapper` somewhere, but only get `ObjectReader` / `ObjectWriter` instances (via helper methods), retain references to those in other places (or dynamically call). These reader/writer objects are not only fully thread-safe wrt reconfiguration, but also very light-weight (wrt mapper instances). So keeping thousands of references does not add much memory usage. – StaxMan Jun 02 '17 at 18:36
  • 2
    So are call to ObjectReader instances not blocking i.e say objectReader.readTree is called in multithreaded application, threads wont be blocked waiting on another thread, using jackson 2.8.x – Xephonia Jan 30 '19 at 11:32
  • 1
    @Xephonia no, calls to `readXxx()` are not blocking and can proceed fully concurrently; esp. for `readTree()`. – StaxMan Feb 20 '21 at 19:22
  • 1
    if readXXX calls aren't blocking, why is static a problem then - why would this "single" instance block threads? – karansardana Apr 24 '21 at 13:20
  • hopefully this answers stays same for question here https://stackoverflow.com/questions/73752793/jacksons-objectmapper-with-rowmapper-in-sql cc @Abhidemon – mattsmith5 Sep 17 '22 at 07:10
  • I'm not sure why but I was having a memory leak when I had my ObjectMapper instance as a static member variable in a utility class, when I made it an instance per call the memory leak ended and also improved the performance (I'm pretty sure my code is not good and that was probably the cause but still for anyone wondering if this coudl be the cause). – Damonio Nov 16 '22 at 05:57
11

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.

Lin_n
  • 189
  • 1
  • 4
  • 7
    But there's a risk of a memory leak as the `ObjectMapper` will be attached to the thread which may be part of a pool. – Kenston Choi Jan 01 '19 at 04:19
  • 1
    @KenstonChoi Should not be a problem, AFAIU. The threads come and go, thread locals come and go with the threads. Depending on the amount of simultaneous threads you may or may not afford the memory, but I don't see "leaks". – Ivan Balashov Apr 01 '19 at 12:05
  • 4
    @IvanBalashov, but if the thread is created/returned from/to a thread pool (e.g., containers like Tomcat), it stays. This may be desired in some cases, but something we need to be aware of. – Kenston Choi Apr 02 '19 at 03:22
3

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 Why are static variables considered evil? (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.

Community
  • 1
  • 1
JBCP
  • 13,109
  • 9
  • 73
  • 111
  • 35
    I would suggest that although static STATEFUL singletons are typically a danger sign, there are enough reasons why in this case sharing a single (or, small number of) instances makes sense. One may want to use Dependency Injection for that; but at the same time it is worth asking whether there is an actual or potential problem to solve. This especially applies to testing: just because something might be problematic in some case does not mean it is for your usage. So: being aware of problems, great. Assuming "one size fits all", not so good. – StaxMan Aug 08 '13 at 20:48
  • 4
    Obviously understanding the issues involved with any design decision is important, and if you can do something without causing problems for your use case you by definition you won't cause any problems. However I would argue there are no benefits to the use of static instances and it opens the door to significant trouble in the future as your code evolves or is handed off to other developers who might not understand your design decisions. If your framework supports alternatives, there is no reason not to avoid static instances, there certainly are no advantages to them. – JBCP Aug 09 '13 at 21:45
  • 11
    I think this discussion goes into very general and less useful tangents. I have no problem suggesting that it is good to be suspicious of static singletons. I just happen to be very familiar for usage for this particular case and I do not think one can reach specific conclusions from set of general guidelines. So I will leave it at that. – StaxMan Aug 10 '13 at 20:35
  • 1
    Late comment, but wouldn't ObjectMapper in particular disagree with this notion? It exposes `readerFor` and `writerFor` which create `ObjectReader` and `ObjectWriter` instances on demand. So I'd say put the mapper with the initial config somewhere static, then get readers/writers with per-case config as you need them? – Carighan Jul 16 '18 at 10:11
  • 1
    @Carighan yes, that seems like a good pattern to me; treat mapper as factory for creating reader/writer instances for actual use. – StaxMan Feb 20 '21 at 19:20
1

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

Harshit
  • 1,174
  • 1
  • 9
  • 24
  • 4
    Make sure to check out latest versions (and perhaps indicate version you use here). There have been improvements to locking based on reported issues, and type resolution (f.ex) was fully rewritten for Jackson 2.7. Although in this case, `TypeReference` is bit expensive thing to use: if possible, resolving it to `JavaType` would avoid quite a bit of processing (`TypeReference`s can not be -- unfortunately -- cached for reasons that I won't dig into here), since they are "fully resolved" (super-type, generic typing etc). – StaxMan Jun 02 '17 at 18:38
1

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;
  }

}
Oliver
  • 1,465
  • 4
  • 17
  • you don't need: private JacksonObjectMapperHolder() { super(); } ... other than that great solution if you need the ObjectMapper and not the reader/writer – Roie Beck Jan 05 '22 at 12:29
  • @RoieBeck I partially agree. The class is `final`, so an implicitly declared constructor is not a problem for inheritance. However, I want to avoid an accidental instantiation, so, I explicitly declare the constructor and mark it `private`. The tedious call to `super` is indicative of my choice to avoid implicit code. – Oliver Jan 05 '22 at 22:17
  • 1
    just giving my 2 cents it's your code :), btw I went with the ThreadLocal solution, as it achieving the same goal, but it is more elegant I think... – Roie Beck Jan 06 '22 at 08:09
  • What is the advantage of this approach over just using a static final field for the ObjectMapper which can be accessed from everywhere? – maxeh Jan 07 '22 at 09:45
  • `ObjectMapper` is thread-safe provided the configuration does not change between serialization/deserialization calls. This approach allows for configuration to change between these calls. All I did was put the `ObjectMapper` instance behind an optimized [double-checked locked](https://en.wikipedia.org/wiki/Double-checked_locking) singleton. – Oliver Jan 07 '22 at 17:13
  • @Oliver I understand how this works, but I'm not sure if this optimized double-checked locking is the right choice in this situation. If you have a class with `private static final ObjectMapper objectMapper = new ObjectMapper();` and a getter for this field, you basically have all you need, or do I miss something here? You can simply do `Class.getInstance()` from everywhere to access it. So my question, why do you need the complicated 30 loc approach if 3 lines are enough? Or do you just prefer to write it like this out of personal taste and because you are used to do it like this? – maxeh Jan 07 '22 at 18:05
  • @maxeh You are right, this is definitely a personal taste. But I don't think the 3-line approach would always work. For example, say you expect the following order: thread A uses serializer or deserializer, thread B changes the configuration, then thread C serializer or deserializer. The 3-line approach may not guarantee order, right? _Disclaimer: I am definitely not a Java multithreading expert, so I may be completely off here._ – Oliver Jan 07 '22 at 18:19
  • 2
    @Oliver well you are right, if you change the config of the objectMapper it is not thread-safe. This is also explained by StaxMan in the accepted answer of this question. However, with your code you have exactly the same issue, so there is no difference between the 30 loc approach and the 3 loc approach, as the problem you describe is related to the state of the objectMapper itself. – maxeh Jan 07 '22 at 19:46