Prior to Jackson 1.2, the only way to serialize or deserialize JSON using Jackson was by using one of the following two methods:

  • Adding annotations to modify the POJO classes
  • Writing custom serializers and deserializers

Now imagine you want to serialize or deserialize a 3rd party POJO which you don’t have access to its source code. What would you do?

Also, you might want your code clean and open to other JSON library, such as GSON.

What would you do to decouple your code from Jackson annotations?

Jackson mix-in annotations helps you resolve this kind of problems. These annotations are used in a mix-in class or interface but function as if they were directly included in the target class.

In this post we will look at how to use the Jackson mix-in annotations.

Sample Application

Let us create a simple Spring Boot application to understand how Jackson mix-in annotation works.

Consider you want serialize or deserialize a User POJO in a Spring Boot application.

Here is code of the User POJO.

User.java

In the preceding code, User is a typical POJO but is not designed to be used with data binding. The User class doesn’t have the default constructor and neither any getter and setter methods.

Let’s assume that you don’t have access to the source code of the User POJO. Or there is some constraint disallowing you to modify the existing POJO. In this scenario, you can’t serialize or deserialize a User object through annotations or by defining your own custom serializer and deserializer.

Let us see how mix-in annotations can solve this problem.

The Jackson Mix-in Class

For mix-in annotation, you first need to define a mix-in class or interface.

Let’s define an abstract mix-in class for User. Ensure that the mix-in class have a constructor matching the source POJO.

Use the @JsonCreator annotation on the constructor and the @JsonProperty property to specify all the properties of the POJO.

Here is code for the UserMixin Jackson mix-in class.

UserMixin.java

UserMixin is an abstract class where the constructor of the class is annotated with @JsonCreator to tell Jackson in what order to pass fields from a JSON object to the constructor.

Each argument of the constructor is annotated with @JsonProperty to indicate the name of the property to bind to.

After creating the UserMixin class, you must configure the ObjectMapper to use the mix-in for the User POJO, like this.

Here is the complete test code to test the Jackson mix-in.

UserTest.java

As you can see in the code, ObjectMapper is configured in the buildMapper() method.

In the test method, an ObjectMapper is created and the addMixIn() method is called on it. The addMixIn() method configures the association between the mix-in and target classes, to be used during serialization.

Here is the output of the Jackson Mix-in test from IntelliJ:

Jackson Mixin Test Results

0
Share

Jackson is a suite of data-processing tools for Java comprising of three components:

  • Streaming (jackson-core) defines low-level streaming API, and includes JSON-specific implementations.
  • Annotations (jackson-annotations) contains standard Jackson annotations
  • Databind (jackson-databind) implements data-binding (and object serialization) support on streaming package. This package depends both on streaming and annotations packages

In this post, I will explain the Java objects to JSON data-binding using Jackson annotations. I will take up each of the Jackson annotations and explain with code snippets how to use them. Each annotation usage is accompanied with proper test cases.

Jackson Serialization and Deserialization Annotations

The Jackson library provides annotations that you can use in POJO’s to control both serialization and deserialization between POJOs and JSON. These annotations that are used in both serialization and deserialization operations are:

  • @JsonIgnore
  • @JsonIgnoreProperties
  • @JsonIgnoreType
  • @JsonAutoDetect

@JsonIgnore

The @JsonIgnore annotation marks a field of a POJO to be ignored by Jackson during serialization and deserialization. Jackson ignores the field both JSON serialization and deserialization. An example of Java class that uses the @JsonIgnore annotation is this.

IgnoreDemoBean.java

The test class to test the @JsonIgnore annotation is this.

IgnoreDemoBeanTest.java

The output on running the test in IntelliJ is this.
@JsonIgnore Annotation Test Output

As you can see, the @JsonIgnore annotation ignored the field personId both during serialization and deserialization.

@JsonIgnoreProperties

The @JsonIgnoreProperties annotation is used at the class level to ignore fields during serialization and deserialization. The properties that are declared in this annotation will not be mapped to the JSON content.

Let us consider an example of Java class that uses the @JsonIgnoreProperties annotation.

IgnorePropertiesDemoBean.java

The test code to test the @JsonIgnoreProperties annotation is this.

IgnorePropertiesDemoBeanTest

The output of running the test in IntelliJ is this.


As you can see, the @JsonIgnoreProperties annotation ignored the field userId and gender both during serialization and deserialization.

@JsonIgnoreType

The @JsonIgnoreType annotation is used to mark a class to be ignored during serialization and deserialization. It marks all the properties of the class to be ignored while generating JSON and reading JSON. An example of Java class that uses the @JsonIgnoreType annotation is this.

IgnoreTypeDemoBean.java

The test code to test the @JsonIgnoreProperties annotation is this.

IgnoreTypeDemoBeanTest.java

The output of running the test in IntelliJ is this.

@JsonAutoDetect

The @JsonAutoDetect annotation is used at the class level to tell Jackson to override the visibility of the properties of a class during serialization and deserialization. You can set the visibility with the following elements:

  • creatorVisibility
  • fieldVisibility
  • getterVisibility
  • setterVisibility
  • isGetterVisibility

The JsonAutoDetect class defines public static constants that are similar to Java class visibility levels. They are:

  • ANY
  • DEFAULT
  • NON_PRIVATE
  • NONE
  • PROTECTED_AND_PRIVATE
  • PUBLIC_ONLY

Let us consider an example of Java class that uses the @JsonAutoDetect annotation.

AutoDetectDemoBean.java

The test code to test the @JsonAutoDetect annotation is this.

The output of running the test in IntelliJ is this.

Jackson Serialization Annotations

Jackson provides several annotations that you can use in POJO’s to serialize Java objects to JSON. These annotations are:

  • @JsonValue
  • @JsonInclude
  • @JsonGetter
  • @JsonAnyGetter
  • @JsonPropertyOrder
  • @JsonRawValue
  • @JsonSerialize
  • @JsonRootName

@JsonValue

The @JsonValue annotation is used at the method level. This annotation tells Jackson to use this method to generate the JSON string from the Java object.

Typically, if you want to print a serialized object, you override the toString() method. But, by using the @JsonValue annotation, you can define the way in which the Java object is to be serialized.

Note: Jackson omits any quotation marks inside the String returned by the custom serializer.
Let us consider an example Java class that uses the @JsonValue annotation.

ValueDemoBean.java

In order to explain the difference between the serialized object with and without the @JsonValue annotation, the code includes the toString() method. You can also run the code without overriding the toString() method.

The test code to test the @JsonValue annotation is this.

ValueDemoBeanTest

The output of running the test in IntelliJ is this.

As shown in the preceding figure, the Java object is serialized by Jackson by calling the defined method toJson(). The quotation marks are added by Jackson.

@JsonInclude

The @JsonInclude annotation is used to exclude properties or fields of a class under certain conditions. This is defined using the JsonInclude.Include enum. This enum contains constants, that determine whether or not to exclude the property. The constants are:

  • ALWAYS
  • NON_DEFAULT
  • NON_EMPTY
  • NON_NULL

Let us consider an example Java class that uses the @JsonInclude annotation.

IncludeDemoBean.java

The test code to test the @JsonInclude annotation is this.

The output of running the test in IntelliJ is this.
@JsonInclude Test Output

As shown in the preceding figure, the JSON string does not contain the property nameas it is initialized to null.

@JsonGetter

The @JsonGetter annotation is used to customize the generated JSON keys. This is accomplished with the value argument of @JsonGetter. The value passed is the name that should be used as the JSON key.

Let us consider an example Java class that uses the @JsonGetter annotation.

GetterDemoBean.java

The test code to test the @JsonGetter annotation is this.

The output of running the test in IntelliJ is this.

As you can see in the example, the Java object is serialized with the property names that you defined using the @JsonGetter annotation. Without the annotations, the serialized JSON would contain the property names:  personId and personName.

@JsonAnyGetter

The @JsonAnyGetter annotation can be used when you don’t want to declare a property or a method for every possible key in JSON. This annotation is used on the getter methods which enables you to use a Map to hold all your properties that you want to serialize.

Let us consider an example Java class that uses the @JsonAnyGetter annotation.

AnyGetterDemoBean.java

The test code to test the @JsonAnyGetter annotation is this.

The output of running the test in IntelliJ is this.

@JsonAnyGetter Test Output
As you can see, all the properties are serialized as the properties of AnyGetterDemoBean object.

@JsonPropertyOrder

The @JsonPropertyOrder annotation tells Jackson to serialize the Java object to JSON, in the order specified as the arguments of the annotation. This annotation also allows partial ordering. The properties are first serialized in the order in which they are found, followed by any other properties not included in the annotation.

Let us consider an example of Java class that uses the @JsonPropertyOrder annotation.

PropertyOrderDemoBean.java

The test code to test the @JsonPropertyOrder annotation is this.

The output of running the test in IntelliJ is this.
@JsonPropertyOrder Test Output

As you can see the result, the name property is first serialized before the personId. Without the @JsonPropertyOrder annotation, the object would have been serialized in the order found in the class.

@JsonRawValue

The @JsonRawValue annotation is used on methods and fields. It tells Jackson to serialize the field or property as declared. For example, if you have a String field in your Java class, the JSON value that Jackson generates is enclosed within quotes (” “). But when you annotate the field with @JsonRawValue, Jackson omits the quotes.

Let us consider an example Java class that explains the use of @JsonRawValue.

RawValueDemoBean.java

Here, the address field is a JSON string. This JSON string will be serialized as a part of the final JSON string of the RawValueDemoBean object.

The test code to test the @JsonRawValue annotation is this.

The output of running the test in IntelliJ is this.

As you can see, the final JSON string of the Java object is generated as defined in the POJO class omitting the quotes.

@JsonSerialize

The @JsonSerialize annotation is used tell Jackson to use the declared custom serializer during the serialization of the field, which is marked with this annotation. Let us consider a POJO that uses the @JsonSerialize annotation.

SerializeDemoBean.java

Next, let us define a custom serializer that will serialize the activeDate field with a specific format.

CustomDateSerializer.java

The code to test the @JsonSerialize annotation is this.

The output of running the test in IntelliJ is this.

@JsonRootName

The @JsonRootName annotation can be used to tell Jackson to wrap the object to be serialized with a top-level element. You can pass the name as a parameter to the @JsonRootName annotation. Let us consider that you want to wrap your serialized Java object with the key user.

Here is an example of Java class that uses the @JsonRootName annotation.

RootNameDemoBean.java

The test code to test the @JsonRootName annotation is this.

The output of running the test in IntelliJ is this.
@JsonRootName Test Output

As you can see, the fields personId and name are wrapped within the user, where the latter is the key, and the former is the value of the property of the generated JSON.

Deserialization Annotations

Let us explore the JSON annotations that can be used to control deserialization of JSON into POJOs. The Jackson deserialization annotations are:

  • @JsonSetter
  • @JsonAnySetter
  • @JsonCreator
  • @JacksonInject
  • @JsonDeserialize

@JsonSetter

The @JsonSetter annotation tells Jackson to deserialize the JSON into Java object using the name given in the setter method. Use this annotation when your JSON property names are different to the fields of the Java object class, and you want to map them.

A Java class that uses the @JsonSetter annotation is this.

SetterDemoBean.java

The @JsonSetter annotation takes the name of the JSON key that must be mapped to the setter method.

The test code to test the @JsonSetter annotation is this.

The output of running the test in IntelliJ is this.

@JsonSetter Test Output

As you can see, the JSON to be serialized has a property id. But no field in the POJO matches this property. Now how will Jackson read this JSON? Here is where the @JsonSetter annotation can be used to map the property id to the field personId. This annotation instructs Jackson to use a setter method for a given JSON property.

@JsonAnySetter

The @JsonAnySetter annotation is used on setter methods of a Map field. Sometimes you may find some JSON values that cannot be mapped to the fields in the Java object class. In such a case, the @JsonAnySetter captures the data and stores them in a Map.

A Java class that uses the @JsonAnySetter annotation is this.

AnySetterDemoBean.java

The test code to test the @JsonAnySetter annotation is this.

The output of running the test in IntelliJ is this.
@JsonAnySetter Test Output

@JsonCreator

The @JsonCreator annotation tells Jackson that the JSON properties can be mapped to the fields of a constructor of the POJO. This is helpful when the JSON properties do not match with the names of the Java object field names. The @JsonCreator annotation can be used where @JsonSetter cannot be used. For example, immutable objects which need their initial values to be injected through constructors.

An example of Java class that uses the @JsonCreator annotation is this.

CreatorDemoBean.java

The test code to test the @JsonCreator annotation is this.

The output of running the test in IntelliJ is this.

@JacksonInject

The @JacksonInject annotation is used to tell Jackson that particular values of the deserialized object will be injected and not read from the JSON string.

An example of Java class where the personId field is injected by Jackson is this.

JacksonInjectDemoBean.java

In order to inject values into a field, you can use the InjectableValues class. You need to configure ObjectMapper to read both, the injected values from injectableValues and the remaining values from the JSON string.

The test code to test the @JacksonInject annotation is this.

The output of running the test in IntelliJ is this.
@JacksonInject Test Output

As you can see, the value for the field personId has been injected by Jackson and the other values are taken from the input JSON string.

@JsonDeserialize

The @JsonDeserialize annotation tells Jackson to use a custom deserializer while deserializing the JSON to Java object. To do so, you need to annotate the field to which you need to apply the custom deserializer.

A Java class that uses the @JsonDeserialize annotation is this.

DeserializeDemoBean.java

The custom deserializer that is referenced by the preceding DeserializeDemoBeanbean class is this.

CustomDateDeserializer.java

Here, the CustomDateDeserializer class extends the StdDeserializer class with a generic type Date. The overriden deserialize() method returns the Date object.

The test code to test the @JsonDeserialize annotation is this.

The output of running the test in IntelliJ is this.
@JsonDeserialize Test Output

General Annotations

The general annotations are:

  • @JsonProperty
  • @JsonFormat
  • @JsonUnwrapped
  • @JsonView
  • @JsonManagedReference and @JsonBackReference
  • @JsonIdentityInfo
  • @JsonFilter

@JsonProperty

The @JsonProperty annotation is used to map property names with JSON keys during serialization and deserialization. By default, if you try to serialize a POJO, the generated JSON will have keys mapped to the fields of the POJO. If you want to override this behavior, you can use the @JsonProperty annotation on the fields. It takes a String attribute that specifies the name that should be mapped to the field during serialization.

You can also use this annotation during deserialization when the property names of the JSON and the field names of the Java object do not match.

Let us consider an example Java class that uses the @JsonProperty annotation.

PropertyDemoBean.java

The test code to test the @JsonProperty annotation is this.

The output of running the test in IntelliJ is this.
@JsonProperty Test Output

@JsonFormat

The @JsonFormat annotation is used to tell Jackson that the format in which the value for a field is serialized. It specifies the format using the JsonFormat.Shape enum.

Let us consider an example Java class that uses the @JsonFormat annotation to modify the Date and Time format of an activeDate field.

FormatDemoBean.java

The test code to test the @JsonFormat annotation is this.

The output of running the test in IntelliJ is this.
@JsonFormat Test Output

@JsonUnwrapped

The @JsonUnwrapped annotation unwraps the values during serialization and deserialization. It helps in rendering the values of a composed class as if they belonged to the parent class. Let us consider an example of Java class that uses the @JsonUnwrapped annotation.

UnwrappedDemoBean.java

In this example, the Address class is inside the UnwrappedDemoBean class. Without the @JsonUnwrapped annotation, the serialized Java object would be similar to this.

Let us see what happens when you use the @JsonUnwrapped annotation.

The test code to test the @JsonUnwrapped annotation is this.

The output of running the test in IntelliJ is this.
@JsonUnwrapped Test Output

As you can see, the Address object is unwrapped and is displayed as the properties of the parent class UnwrappedDemoBean.

@JsonView

The @JsonView annotation is used to include or exclude a property dynamically during serialization and deserialization. It tells the view in which the properties are rendered. Let us consider an example Java class that uses the @JsonView annotation with Public and Internal views.

ViewDemoBean.java

The test code to test the @JsonView annotation is this.

As you can see in the test code, you need to configure the ObjectMapper to include which type of view must be used for writing the JSON from the Java object using the writerWithView() method.

The output of running the test in IntelliJ is this.

When the JSON is generated in the public view, only personId and name fields are serialized omitting the gender field. But when the JSON is generated in the internal view all the fields are serialized.

@JsonManagedReference and @JsonBackReference

The @JsonManagedReference and @JsonBackReference annotation are used to create JSON structures that have a bidirectional relationship. Without this annotation, you get an error like this.

Let us consider an example Java class that uses the @JsonManagedReference and @JsonBackReference annotations.

ManagedReferenceDemoBean.java

BackReferenceDemoBean.java

The test code to test both @JsonManagedReference and @JsonBackReference annotations is this.

The output of running the test in IntelliJ is this.
@BackReferenceDemoBean and @ManagedReferenceDemoBean Test Output

As you can see, the field marked with @JsonManagedReference is the forward reference which will be included during serialization. The field marked with @JsonBackReference is the back reference and is usually omitted during serialization.

@JsonIdentityInfo

The @JsonIdentityInfo tells Jackson to perform serialization or deserialization using the identity of the object. This annotation works similar to the @JsonManagedReference and @JsonBackReference annotations with the difference that @JsonIdentityInfo includes the back reference object.

Let us consider an example where the IdentityInfoEmployeeDemoBean has a bidirectional relationship with IdentityInfoManagerDemoBean using the @JsonIdentityInfo annotation.

IdentityInfoEmployeeDemoBean.java

IdentityInfoManagerDemoBean.java

The test code to test the @JsonIdentityInfo annotation is this.

The output of running the test in IntelliJ is this.
@JsonIdentityInfo Test Output

As you can see, the output gives the information about the employee with his manager details. It also provides the additional information about the employees under the manager.

@JsonFilter

The @JsonFilter annotation is used to tell Jackson to use a custom defined filter to serialize the Java object. To define your filter, you need to use the FilterProvider class. This provider gets the actual filter instance to use. The filter is then configured by assigning the FilterProvider to ObjectMapper.

Let us consider an example of Java class that uses the @JsonFilter annotation.

FilterDemoBean.java

The test code to test the @JsonFilter annotation is this.

The output of running the test in IntelliJ is this.

@JsonFilter Test Output
As you can see, the custom filter declared as the arguments of the @JsonFilter annotation extract only the name and filters out the other properties of the bean during serialization.

You can download the source code of this post from here.

0
Share

Its not uncommon for computers to need to communicate with each other. In the early days this was done with simple string messages. Which was problematic. There was no standard language. XML evolved to address this. XML provides a very structured way of sharing data between systems. XML is so structured, many find it too restrictive. JSON is a popular alternative to XML. JSON offers a lighter and more forgiving syntax than XML.

JSON is a text-based data interchange format that is lightweight, language independent, and easy for humans to read and write. In the current enterprise, JSON is used for enterprise messaging, communicating with RESTful web services, and AJAX-based communications. JSON is also extensively used by NoSQL database such as, MongoDB, Oracle NoSQL Database, and Oracle Berkeley DB to store records as JSON documents. Traditional relational databases, such as PostgreSQL is also constantly gaining more JSON capabilities. Oracle Database also supports JSON data natively with features, such as transactions, indexing, declarative querying, and views.

In Java development, you will often need to read in JSON data, or provide JSON data as an output. You could of course do this on your own, or use an open source implementation. For Java developers, there are several options to choose from. Jackson is very popular choice for processing JSON data in Java.

Maven Dependencies for Jackson

The Jackson library is composed of three components: Jackson Databind, Core, and Annotation. Jackson Databind has internal dependencies on Jackson Core and Annotation. Therefore, adding Jackson Databind to your Maven POM dependency list will include the other dependencies as well.

Spring Boot and Jackson

The above dependency declaration will work for other Java projects, but in a Spring Boot application, you may encounter errors such as this.

Jackson Dependency Conflict Error - NoSuchMethod Error

The Spring Boot parent POM includes Jackson dependencies. When you include the version number, thus overriding the Spring Boot curated dependency versions you may encounter version conflicts.

The proper way for Jackson dependency declaration is to use the Spring Boot curated dependency by not including the version tag on the main Jackson library, like this.

NOTE: This problem is highly dependent on the version of Spring Boot you are using.

For more details on this issue, check out my post Jackson Dependency Issue in Spring Boot with Maven Build.

Reading JSON – Data Binding in Jackson

Data binding is a JSON processing model that allows for seamless conversion between JSON data and Java objects. With data binding, you create POJOs following JavaBeans convention with properties corresponding to the JSON data. The Jackson ObjectMapper is responsible for mapping the JSON data to the POJOs. To understand how the mapping happens, let’s create a JSON file representing data of an employee.

employee.json

The preceding JSON is composed of several JSON objects with name-value pairs and a phoneNumbers array. Based on the JSON data, we’ll create two POJOs: Address and Employee. The Employee object will be composed of Address and will contain properties with getter and setter method corresponding to the JSON constructs.

When Jackson maps JSON to POJOs, it inspects the setter methods. Jackson by default maps a key for the JSON field with the setter method name. For Example, Jackson will map the name JSON field with the setName() setter method in a POJO.

With these rules in mind, let’s write the POJOs.

Address.java

Employee.java

With the POJOs ready to be populated with JSON data, let’s use ObjectMapper of Jackson to perform the binding.

ObjectMapperDemo.java

In the ObjectMapperDemo class above, we created an ObjectMapper object and called its overloaded readValue() method passing two parameters. We passed a File object representing the JSON file as the first parameter. And Employee.class as the target to map the JSON values as the second parameter. The readValue() method returns an Employee object populated with the data read from the JSON file.

The test class for ObjectMapperDemo is this.

ObjectMapperDemoTest.java

The output on running the test is this.

Output of ObjectMapperDemo

Simple Data Binding in Jackson

The example above we covered full data binding – a variant of Jackson data binding that reads JSON into application-specific JavaBeans types. The other type is simple data binding where you read JSON into built-in Java types, such as Map and List and also wrapper types, such as String, Boolean, and Number.

An example of simple data binding is to bind the data of employee.json to a generic Map is this.

ObjectMapperToMapDemo.java

In the ObjectMapperToMapDemo class above, notice the overloaded readValue() method where we used a FileInputStream to read employee.json. Other overloaded versions of this method allow you to read JSON from String, Reader, URL, and byte array. Once ObjectMapper maps the JSON data to the declared Map, we iterated over and logged the map entries.

The test class for the ObjectMapperToMapDemo class is this.

ObjectMapperToMapDemoTest.java

The output on running the test is this.
Output of ObjectMapperToMapDemo

With simple data binding, we don’t require writing JavaBeans with properties corresponding to the JSON data. This is particularly useful in situations where we don’t know about the JSON data to process. In such situations, another approach is to use the JSON Tree Model that I will discuss next.

Reading JSON into a Tree Model

In the JSON Tree Model, the ObjectMapper constructs a hierarchical tree of nodes from JSON data. If you are familiar with XML processing, you can relate the JSON Tree Model with XML DOM Model. In the JSON Tree Model, each node in the tree is of the JsonNode type, and represents a piece of JSON data. In the Tree Model, you can randomly access nodes with the different methods that JsonNode provides.

The code to generate a Tree Model of the employee.json file is this.

In the constructor of the JsonNodeDemo class above, we created an ObjectMapper instance and called its readTree() method passing a File object representing the JSON document as parameter. The readTree() method returns a JsonNode object that represents the hierarchical tree of employee.json. In the readJsonWithJsonNode() method, we used the ObjectMapper to write the hierarchical tree to a string using the default pretty printer for indentation.

The output on running the code is this.

Next, let’s access the value of the name node with this code.

In the code above, we called the path() method on the JsonNode object that represents the root node. To the path() method, we passed the name of the node to access, which in this example is name. We then called the asText() method on the