Should I Declare Jackson's Objectmapper as a Static Field

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 fly

  • ObjectMapper 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 ObjectReaders 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



Leave a reply



Submit