Should I declare Jackson's ObjectMapper as a static field?
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();
}
Solution 1:
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:
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:
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.