This project contains several examples showing how we can use Jackson to handle marshalling and unmarshalling Java objects to and from JSON.
-
Example 01: A basic example. We can see in
Example01Main
how theObjectMapper
class provided to us by Jackson, can be used to read and write Java objects as JSON. We can also note that theBook
class being read / written has nothing special about it - it's just a plain old Java object (POJO) with no annotations, or inheritance. Basic classes like this will be handled automatically. We can also see that theGenre
enum is handled perfectly with no additional configuration. -
Example 02: Here we can see a (somewhat contrived) example showing how the
@JsonGetter
and@JsonSetter
annotations can be used to override the default JSON property names that would be generated by Jackson. We can also see the@JsonIgnore
can be used to ignore a particular property (i.e. it won't be written out to JSON). -
Example 03: In this example, our
Pokemon
class has a list oftypes
. With no additional configuration, Jackson will marshall and unmarshall this correctly. However, as shown byExample03Main
lines 15 and 24, the deserialized list type will always beArrayList
, even though it was originally created as aLinkedList
. Do keep this in mind. -
Example 04: In this example, we can see that
Map
s are also able to be marshalled / unmarshalled with no additional configuration, assuming the map's key type isString
. However, also note that, as shown byExample04Main
lines 15 and 24, the deserialized map type will always beLinkedHashMap
, no matter the type of the original map. -
Example 05: In this example, we can see how we can provide custom serialization and deserialization of certain types, which may not be naturally supported by Jackson. We do this by subclassing
StdSerializer
andStdDeserializer
, and then referring to our implementations using the@JsonSerialize
and@JsonDeserialize
annotations. In this example,Movie
has a release date, which is of typeLocalDate
. This is not naturally supported by Jackson, so we have writtenLocalDateSerializer
andLocalDateDeserializer
classes to handle this.In Example 05, we also see that we have a
University
class, which keeps track of enrollments by mappingCourse
instances to theStudent
s taking those courses. Jackson doesn't naturally supportMap
s with non-String
key types. To solve this problem, we have provided aCourseDeserializer
class, which is a subclass ofKeyDeserializer
. We then tell Jackson to use this class with another@JsonDeserialize
annotation, this with thekeyUsing
property set. -
Example 06: In this example, we can see how we might overcome issues caused by cyclic references. In this example, each
Employee
instance holds a reference to theirManager
. Managers in turn hold references to all of their employees. With no additional configuration, this would result in an infinite loop whenever we tried to serialize one of these instances. To get around this, we have used the@JsonIdentifyInfo
annotation on theEmployee
class, specifying that each employee can be uniquely identified by itsid
property. Whenever an employee is first serialized, the entire employee will be written out. If an employee with the same id is then serialized later on, only itsid
value will be written out instead.Using this method helps overcome the cyclic reference problem, but requires that the unmarshaller on the receiving end knows how to unmarshall JSON which has been written out this way (for example, another app using Jackson). This removes some benefits of using an otherwise platform-independent data interchange format such as JSON. When designing your data objects intended for conversion to / from JSON, consider whether any cyclic references are necessary in the first place.
-
Example 07: In this example, we can see how we can deal with inheritance using Jackson.
Zoo
s have a collection ofAnimal
s, which may be eitherCat
s orDog
s. With no configuration, Jackson will be able to serialize aZoo
correctly, but will be unable to deserialize one - it will try to createAnimal
objects rather thanCat
andDog
objects. This is not allowed asAnimal
is abstract (and even if it were allowed, we would lose any cat- and dog-specific information).We can handle this by using the
@JsonTypeInfo
annotation onAnimal
, which will allow Jackson to add extra info when serializing, that it can use when deserializing to determine the object type. theuse
property lets us specify eitherNAME
orCLASS
. If we specifyNAME
, then we additionally need to supply a@JsonSubTypes
annotation mapping classes to names. If we useCLASS
, then Jackson will simply use the fully qualified (i.e. including package) Java class name. Theproperty
property lets us specify the name of the extra JSON property into which Jackson will write the type info.