Should I declare Jackson's ObjectMapper as a static field?
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).
What is the advantage of declaring ObjectMapper as a bean?
Here is the API note about ObjectMapper
Mapper instances are fully thread-safe provided that ALL configuration of the instance occurs before ANY read or write calls. If configuration of a mapper is modified after first usage, changes may or may not take effect, and configuration calls themselves may fail.
And here is guideline to improve jackson performance:
Reuse heavy-weight objects: ObjectMapper (data-binding) and JsonFactory (streaming API)
To a lesser degree, you may also want to reuse ObjectReader and ObjectWriter instances -- this is just some icing on the cake, but they are fully thread-safe and reusable
So to summarize:
ObjectMapper
is thread-safe, as long as you did not change your configuration on the flyObjectMapper
initialization is a heavy operation
Therefore, declare your ObjectMapper
as @Bean
will:
Improve parsing performance (as you do not need to re-init the instance when parsing)
Reduce memory usage (less objects created)
Your
ObjectMapper
returned from@Bean
method is fully configured. It is thread-safe. (But do obviously, do not modify the@Autowired
instance XD)Give common configuration for your application (like timezone, null fail-over config...)
Should I declare Jackson's ObjectMapper every time I need it?
I found that the instantiation new ObjectMapper() takes quite long, so you should definitely reuse the object rather than creating it every time before repeated use.
I usually declare it like a logger in the class that'S using it (but of course it depends on your specific requirements whether this makes sense for you):
private static final ObjectMapper objectMapper = new ObjectMapper();
ObjectMapper - Best practice for thread-safety and performance
private static final ObjectMapper jsonMapper = new ObjectMapper();
Constructing an ObjectMapper
instance is a relatively expensive operation, so it's recommended to create one object and reuse it. You did it right making it final
.
// Suggestion 1:
public static <T> T toObject1(final Class<T> type, final String json) throws IOException {
return jsonMapper.readValue(json, type);
}
You always read JSON to a POJO, so let's be precise and clear, and use ObjectReader
.
// Suggestion 2:
public static <T> T toObject2(final Class<T> type, final String json) throws IOException {
return jsonMapper.readerFor(type).readValue(json);
}
// Suggestion 3:
public static <T> T toObject3(final Class<T> type, final String json) throws IOException {
return jsonReader.forType(type).readValue(json);
}
There is no difference, really. Both methods will construct a new ObjectReader
object: the former (jsonMapper.readerFor(type)
) will give you a fully-built instance directly, the latter (jsonReader.forType(type)
) will complement the not-yet-usable jsonReader
and returns a ready-to-use object. I would rather go with option 2 because I don't want to keep that field.
You shouldn't worry about performance or thread-safety. Even though creating an ObjectMapper
might be costly (or making a copy out of it), getting and working with ObjectReader
s is lightweight and completely thread-safe.
From the Java documentation (emphasis mine):
Uses "mutant factory" pattern so that instances are immutable (and thus fully thread-safe with no external synchronization); new instances are constructed for different configurations. Instances are initially constructed by
ObjectMapper
and can be reused, shared, cached; both because of thread-safety and because instances are relatively light-weight.
I recently had these questions myself and decided on ObjectMapper#reader(InjectableValues)
as a factory method. It's very handy particularly when you want to customise an ObjectReader
slightly or, as it was in my case, to adjust a DeserializationContext
.
That's an excellent question, by the way.
How do I correctly reuse Jackson ObjectMapper?
It's fine to use a single instance per application provided you don't call any configuration methods after it's been made visible i.e. you should do all your initialization inside a static block.
Is it safe to use a static object in a non-static method when multiple threads are accessing it?
This depends on the implementation of ObjectMapper
. For a possible answer, see:
Should I declare Jackson's ObjectMapper as a static field?
It is not possible to tell from the code sample you have provided because we don't know what that ObjectMapper
is.
To find the answer you would need to check the javadoc of ObjectMapper
. Or failing that, the implementation.
If you are unsure, you could:
- create a new
ObjectMapper
inside the method so there is a new object each time, - create a ThreadLocal, so each thread has it's own object
Creating objects is very cheap on the JVM (unless they do expensive operations like scanning the class path, etc).
Jackson's ObjectMapper().writeValueAsString() ignores variables that begin with is_
Jackson apparently scans the class that you pass in for getters and setters
and then use those methods for serialization and deserialization.
"Get", "Set", "is" are eliminated and what remains in those methods will be used as Json field.
Hence your "is_something" is changed into "_something" and so on.
Jackson ObjectMapper in Static Method with Generics
Java Generics are implemented using "type erasure". That means the compiler can check the type safety and the types get removed at run time.
So you can't use your type variables ("N") like that. You have to pass the actual class as an argument:
public static <N, T extends AbstractRESTApplication> N GET_PAYLOAD( T app,
String urlString, REQUEST_TYPE requestType,
Class<N> nClass) throws ... {
return om.readValue(content.toString(), nClass);
Related Topics
Java Streams: Replacing Groupingby and Reducing by Tomap
Populating Spring @Value During Unit Test
Coding Conventions - Naming Enums
Parsing JSON in Java Without Knowing JSON Format
Java.Util.Zip.Zipexception: Error in Opening Zip File
How to Access Resources in Jar File
How to Convert a 3D Point into 2D Perspective Projection
Convert JSON String to Pretty Print JSON Output Using Jackson
How to Customise the Jackson JSON Mapper Implicitly Used by Spring Boot
What Happens When You Increment an Integer Beyond Its Max Value
Differencebetween 'Java', 'Javaw', and 'Javaws'
Converting Integer to String with Comma for Thousands
The Meaning of Noinitialcontextexception Error
No-Throw Virtualmachineerror Guarantees