Jackson Json Annotations Example

Previous data-binding posts gave the idea about how the POJO’s are mapped to JSON and viceversa using ObjectMapper API. This post will demonstrate same POJO to JSON Data-binding example using commonly used Jackson JSON Annotations. Basic operations read/write will be implemented exactly as before, but POJO’s are annotated this time. Let’s get going.

We will start with code and explain each part subsequently. Be with us.

Step 1: Include JACKSON dependency in pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.websystique.json</groupId>
	<artifactId>JacksonAnnotationsExample</artifactId>
	<version>1.0.0</version>
	<packaging>jar</packaging>

	<name>JacksonAnnotationsExample</name>


	<dependencies>
		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-databind</artifactId>
			<version>2.5.3</version>
		</dependency>
		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-annotations</artifactId>
			<version>2.5.3</version>
		</dependency>
	</dependencies>
</project>

jackson-databind is required in order to use ObjectMapper API. jackson-annotations is needed so that JSON annotations can be used in POJO.

Step 2 : Declare Input JSON

inputfile.json

{"name":"AUDI","carModel":2014,"price":30000,"foo":"bar","tom":"jerry","ignoreme1":"ig1","ignoreme2":"ig2","colors":["GRAY","BLACK","WHITE"],"promoDate":1399647200000}

We will be mapping this Input JSON to our POJO (declared below).

Step 3 : Declare POJO

package com.websystique.json.jackson.model;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;

@JsonIgnoreProperties({ "ignoreme1", "ignoreme2" })
public class Car {

	@JsonProperty
	private String name;

	@JsonProperty("carModel")
	private int model;

	@JsonProperty
	private String price;

	private String ignoreme1;

	private String ignoreme2;

	@JsonProperty
	private List<String> colors = new ArrayList<String>();

	@JsonProperty
	@JsonSerialize(using = CustomDateSerializer.class)
	private Date promoDate;

	private Map<String, Object> otherProperties = new HashMap<String, Object>();

	@JsonAnyGetter
	public Map<String, Object> any() {
		return otherProperties;
	}

	@JsonAnySetter
	public void set(String name, Object value) {
		otherProperties.put(name, value);
	}

	@Override
	public String toString() {
		return "Car [name=" + name + ", model=" + model + ", price=" + price
				+ ", ignoreme1=" + ignoreme1 + ", ignoreme2=" + ignoreme2
				+ ", colors=" + colors + ", promoDate=" + promoDate
				+ ", otherProperties=" + otherProperties + "]";
	}

}

Step 3 : Create Serialization Helper [Optional]

Just for the sake of showing a handy and popular customization annotation, we created this class. This is used on annotated Pojo ‘promoDate’ property. Explanation is provided further in post.

package com.websystique.json.jackson.model;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;

public class CustomDateSerializer extends JsonSerializer<Date>{

	private static final SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
	
	@Override
	public void serialize(Date date, JsonGenerator generator, SerializerProvider provider)
			throws IOException, JsonProcessingException {
		String formattedDate = dateFormat.format(date);
		generator.writeString(formattedDate);
	}
	
	
}

Step 5 : Create Main

package com.websystique.json.jackson;

import java.io.File;
import java.io.IOException;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.websystique.json.jackson.model.Car;

public class JsonJacksonAnnotationsDemo {

	public static void main(String args[]) throws JsonParseException,
			JsonMappingException, IOException {

		ObjectMapper mapper = new ObjectMapper();
		Car car = mapper.readValue(new File("inputfile.json"), Car.class);

		mapper.writeValue(new File("outputfile.json"), car);
		System.out.println(car);

	}
}

Main is pretty straight forward. First we deserialize the input JSON into a POJO using ObjectMapper readValue which simply reads from a file. Then we serialize the same POJO using writeValue and writes the JSON to a file.

Below is the output after running above Main:

Car [name=AUDI, model=2014, price=30000, ignoreme1=null, ignoreme2=null, colors=[GRAY, BLACK, WHITE], promoDate=Fri May 09 16:53:20 CEST 2014, otherProperties={tom=jerry, foo=bar}]

Below is the content of outputfile.json after running above Main:

{"name":"AUDI","price":"30000","colors":["GRAY","BLACK","WHITE"],"promoDate":"09/05/2014","carModel":2014,"tom":"jerry","foo":"bar"}

Annotations Explained:

1) @JsonProperty : This annotation can be used on a property or method which will be used for Serialization and Deserialization of JSON. It takes an optional ‘name’ parameter which is useful in case the property name is different than ‘key’ name in json.

When to use:
– If you just want to declare property and not getter/setters.
– If you are using property and getter/setters BUT want to use a different getter/setter or property name than the one coming in JSON [‘key’ name]. Just set the name parameter in annotations with actual ‘key’ in JSON.

For example, above POJO [car.java] does not contains any getter/setter for individual property. Instead only the properties are declared and annotated with @JsonProperty. By default, if key name matches with property name, value is mapped to property value. But you can provide a name attribute in case the key name in input is different than property name in POJO [e.g. model property is mapped to carModel input]

2) @JsonIgnoreProperties : This Class level annotation can be used to prevent certain properties to be serialized & deserialized. What it means is that they will not be mapped to JSON content.

When to use:
– If you want to ignore serialization/deserialization of certain properties [For example some properties are valid in past but not anymore].

For example, In our case, we don’t want property “ignoreme1” & “ignoreme2” to be mapped. So we have included these properties in JsonIgnoreProperties. You can see from content of outputfile.json that it does not contain ignoreme1 & ignoreme2 (means they were not serialized). Similarly, from toString output it is clear that ignoreme1 & ignoreme2 were not deserailzed (they did not contain any value).

3) @JsonAnySetter, @JsonAnyGetter : These annotations works as a Catch-All and are applied on Getters/Setter working with a Map. If there is any JSON value which is not mapped to a property in POJO, then that value can be caught by @JsonAnySetter, and stored (deserialized) into Map. Similarly the values which are stored into Map can be serialized back to JSON using @JsonAnyGetter.

When to use:
– If you don’t want to declare a property or method for every possible ‘key’ in JSON, but still want to capture(serialize/deserialize) the data.

For example, in our case, wee don’t have properties ‘tom’ or ‘foo’ defined in pojo. But by using @JsonAnySetter & @JsonAnyGetter, we were able to store those values(deserialized) [otherProperties={tom=jerry, foo=bar}] and create them again(serialized)[“tom”:”jerry”,”foo”:”bar”].

4) @JsonSerialize : This annotation can be used to change[or customize] the default serialization (Java to JSON) process.

When to use:
– When default serialization is not fitting your needs and you want a custom behavior to be applied.

For example, in our input JSON, the “promoDate” field {“promoDate”:1399647200000} contains date in milliseconds format. In case we want to write the date in some other format(dd/MM/yyyy e.g.), we can do so using a Custom Serializer. We wrote one CustomDateSerializer. So before writing JSON output, this serializer will be called for applicable field(the one annotated with @JsonSerialize(using = CustomDateSerializer.class), and as a result convert the output in desired format before writing that output.

These were few of the commonly used annotations. For complete list of Jackson annotations, please refer to JavaDocs

That’s it. In the next post, we will see another popular json library Google GSON , and it’s usage.

References