ObjectMapper provides functionality for reading and writing JSON,
either to and from basic POJOs (Plain Old Java Objects), or to and from
a general-purpose JSON Tree Model (
JsonNode), as well as
related functionality for performing conversions.
It is also highly customizable to work both with different styles of JSON
content, and to support more advanced Object concepts such as
polymorphism and Object identity.
ObjectMapper
also acts as a factory for more advanced
ObjectReaderand
ObjectWriter classes.
Mapper (and
ObjectReaders,
ObjectWriters it constructs) will
use instances of
JsonParser and
JsonGeneratorfor implementing actual reading/writing of JSON.
Note that although most read and write methods are exposed through this class,
some of the functionality is only exposed via
ObjectReader and
ObjectWriter: specifically, reading/writing of longer sequences of
values is only available through
ObjectReader#readValues(InputStream)and
ObjectWriter#writeValues(OutputStream).
Simplest usage is of form:
final ObjectMapper mapper = new ObjectMapper(); // can use static singleton, inject: just make sure to reuse!
MyValue value = new MyValue();
// ... and configure
File newState = new File("my-stuff.json");
mapper.writeValue(newState, value); // writes JSON serialization of MyValue instance
// or, read
MyValue older = mapper.readValue(new File("my-older-stuff.json"), MyValue.class);
// Or if you prefer JSON Tree representation:
JsonNode root = mapper.readTree(newState);
// and find values by, for example, using a
com.fasterxml.jackson.core.JsonPointer expression:
int age = root.at("/personal/age").getValueAsInt();
The main conversion API is defined in
ObjectCodec, so that
implementation details of this class need not be exposed to
streaming parser and generator classes. Usage via
ObjectCodec is,
however, usually only for cases where dependency to
ObjectMapper is
either not possible (from Streaming API), or undesireable (when only relying
on Streaming API).
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 instance
is modified after first usage, changes may or may not take effect, and configuration
calls themselves may fail.
If you need to use different configuration, you have two main possibilities:
- Construct and use
ObjectReader for reading,
ObjectWriter for writing.
Both types are fully immutable and you can freely create new instances with different
configuration using either factory methods of
ObjectMapper, or readers/writers
themselves. Construction of new
ObjectReaders and
ObjectWriters is
a very light-weight operation so it is usually appropriate to create these on per-call
basis, as needed, for configuring things like optional indentation of JSON.
- If the specific kind of configurability is not available via
ObjectReader and
ObjectWriter, you may need to use multiple
ObjectMapper instead (for example:
you cannot change mix-in annotations on-the-fly; or, set of custom (de)serializers).
To help with this usage, you may want to use method
#copy() which creates a clone
of the mapper with specific configuration, and allows configuration of the copied instance
before it gets used. Note that
#copy operation is as expensive as constructing
a new
ObjectMapper instance: if possible, you should still pool and reuse mappers
if you intend to use them for multiple operations.
Note on caching: root-level deserializers are always cached, and accessed
using full (generics-aware) type information. This is different from
caching of referenced types, which is more limited and is done only
for a subset of all deserializer types. The main reason for difference
is that at root-level there is no incoming reference (and hence no
referencing property, no referral information or annotations to
produce differing deserializers), and that the performance impact
greatest at root level (since it'll essentially cache the full
graph of deserializers involved).
Notes on security: use "default typing" feature (see
#enableDefaultTyping())
is a potential security risk, if used with untrusted content (content generated by
untrusted external parties). If so, you may want to construct a custom
TypeResolverBuilder implementation to limit possible types to instantiate,
(using
#setDefaultTyping).