JSON is short for JavaScript Object Notation. JSON is a popular data exchange format between browsers and web servers because the browsers can parse JSON into JavaScript objects natively. On the server, however, JSON needs to be parsed and generated using JSON APIs. This Java JSON tutorial focuses on the various choices you have for parsing and generating JSON in Java.
This Java JSON tutorial consists of many pages. Each page describes a different aspect of e.g. a Java JSON API, or of working with JSON in Java in general. This page is only the frontpage / first page of this Java JSON tutorial. See the left menu for a list of all pages in this Java JSON tutorial.
Java JSON APIs
When JSON first became popular Java did not have a standard JSON parser / generator implementation. Instead Java developers had to rely on open source Java JSON APIs. Since then Java has attempted to address the missing Java JSON API in JSR 353. Keep in mind that JSR 353 is not yet an official standard (as I am writing this).
The Java community has also developed several open source Java JSON APIs. The open source Java JSON APIs often offer more choice and flexibility in how you can work with JSON than the JSR 353 API. Therefore the open source APIs are still decent options. Some of the more well-known open source Java JSON APIs are:
- Jackson
- GSON
- Boon
- JSON.org
If you prefer to use a JSR 353 compliant JSON parser you can use JSONP.
Both the open source and JSONP Java JSON APIs will be covered in a bit more detail in the following sections.
Jackson
Jackson is a Java JSON API which provides several different ways to work with JSON. Jackson is one of the most popular Java JSON APIs out there. You can find Jackson here:
Jackson contains 2 different JSON parsers:
- The Jackson ObjectMapper which parses JSON into custom Java objects, or into a Jackson specific tree structure (tree model).
- The Jackson JsonParser which is Jackson's JSON pull parser, parsing JSON one token at a time.
Jackson also contains two JSON generators:
- The Jackson ObjectMapper which can generate JSON from custom Java objects, or from a Jackson specific tree structure (tree model).
- The Jackson JsonGenerator which can generate JSON one token at a time.
---------------------------
Jackson Installation
The Java JSON API called Jackson consists of one core JAR file (project) and two other JAR files that use the core JAR file. The three JAR files (projects) in the Jackson JSON API are:
In order to "install" Jackson in your Java application you need to add these JAR files to the classpath of your application. There are several ways to do so. I will cover two here.
Before you even start adding the Jackson JAR files to your classpath, you need to decide what version of the Jackson JSON API to use. To do so, go to the Jackson website and see what versions are available. If you are not already using a specific version of Jackson in your project, use the latest stable version. Write the version number down. You may need it later.
You can find a list of Jackson releases here:
https://github.com/FasterXML/jackson-core/releases
Note, that both
http://search.maven.org
Search for the project you want to use (e.g.
Once the JAR files are downloaded, add them to the classpath of your project. You can do so within your IDE, and / or within the scripts (bash or cmd) you use to run your application.
----------------------------------
- Jackson Core
- Jackson Annotations
- Jackson Databind
In order to "install" Jackson in your Java application you need to add these JAR files to the classpath of your application. There are several ways to do so. I will cover two here.
Adding the JAR Files to Your Classpath
In order to use any of the Jackson projects (JAR files) you must add the corresponding JAR file to the classpath of your application. You can do so in several different ways.Before you even start adding the Jackson JAR files to your classpath, you need to decide what version of the Jackson JSON API to use. To do so, go to the Jackson website and see what versions are available. If you are not already using a specific version of Jackson in your project, use the latest stable version. Write the version number down. You may need it later.
You can find a list of Jackson releases here:
https://github.com/FasterXML/jackson-core/releases
Jackson Maven Dependencies
If your project uses Maven to build (and resolve + download dependencies), you need to add Jackson as a dependency to your project's POM file. Here is how Jackson as Maven dependencies look:Note, that both
jackson-annotations
and jackson-databind
have "transitive dependencies" to jackson-core
(and jackson-databind
to jackson-annotations
). This means, that if you plan to use the jackson-databind
project, you just need to include that as dependency in your Maven POM file. Then it will transitively include the other two projects as dependencies. Regardless, I like to add my dependencies explicitly so I can see what I am using (but that's just me).Adding the JAR Files Directly to the Classpath
Another option is to add the Jackson JAR files directly to the classpath of your application. To do so you must first download the JAR files. You can download the finished JAR files via the central Maven repository. Go to:http://search.maven.org
Search for the project you want to use (e.g.
jackson-core
, jackson-annotation
or jackson-databind
). Once you find the right project, make sure you click the "all versions" link next to the version number in the search result. That will show you a list of the previous versions of that project. Click around until you find a link directly to the JAR file for that project and that version. Then download the JAR file.Once the JAR files are downloaded, add them to the classpath of your project. You can do so within your IDE, and / or within the scripts (bash or cmd) you use to run your application.
----------------------------------
Jackson ObjectMapper
The Jackson ObjectMapper class (
The Jackson ObjectMapper can also create JSON from Java objects. Generating JSON from Java objects is also referred to as to serialize Java objects into JSON.
The Jackson Object mapper can parse JSON into objects of classes developed by you, or into objects of the built-in JSON tree model explained later in this tutorial.
By default Jackson maps the fields of a JSON object to fields in a Java object by matching the names of the JSON field to the getter and setter methods in the Java object. Jackson removes the "get" and "set" part of the names of the getter and setter methods, and converts the first character of the remaining name to lowercase.
For instance, the JSON field named
If you need to match JSON object fields to Java object fields in a different way, you need to either use a custom serializer and deserializer, or use some of the many Jackson Annotations.
Reading arrays of objects also works with other JSON sources than a string. For instance, a file, URL,
However, sometimes it should be allowed to have more fields in the JSON than in the corresponding Java object. For instance, if you are parsing JSON from a REST service which contains much more data than you need. In that case, Jackson enables you to ignore these extra fields with a Jackson configuration. Here is how configuring the Jackson
Here is an example of reading a Java
Here is how you register and use a custom deserializer with the Jackson
The
Jackson enables you to set a custom serializer on the
The Jackson tree model is represented by the
Regardless of whether you are accessing a field, array or nested object you use the
This concludes this Jackson ObjectMapper tutorial. I hope you found this tutorial useful!
com.fasterxml.jackson.databind.ObjectMapper
) is the simplest way to parse JSON with Jackson. The Jackson ObjectMapper
can parse JSON from a string, stream or file, and create a Java object or object graph representing the parsed JSON. Parsing JSON into Java objects is also referred to as to deserialize Java objects from JSON.The Jackson ObjectMapper can also create JSON from Java objects. Generating JSON from Java objects is also referred to as to serialize Java objects into JSON.
The Jackson Object mapper can parse JSON into objects of classes developed by you, or into objects of the built-in JSON tree model explained later in this tutorial.
Jackson Databind
TheObjectMapper
is located in the Jackson Databind project, so your application will need that project on its classpath to work. See the Jackson Installation tutorial for more information.Jackson ObjectMapper Example
Here is a quick Java JacksonObjectMapper
example:ObjectMapper objectMapper = new ObjectMapper();
String carJson =
"{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";
try {
Car car = objectMapper.readValue(carJson, Car.class);
System.out.println("car brand = " + car.getBrand());
System.out.println("car doors = " + car.getDoors());
} catch (IOException e) {
e.printStackTrace();
}
The Car
class was made by me. As you can see, the Car.class
is parsed as the second parameter to the readValue()
method. The first parameter of readValue()
is the source of the JSON (string, stream or file). Here is how the Car
class looks:public class Car {
private String brand = null;
private int doors = 0;
public String getBrand() { return this.brand; }
public void setBrand(String brand){ this.brand = brand;}
public int getDoors() { return this.doors; }
public void setDoors (int doors) { this.doors = doors; }
}
How Jackson ObjectMapper Matches JSON Fields to Java Fields
To read Java objects from JSON with Jackson properly, it is important to know how Jackson maps the fields of a JSON object to the fields of a Java object, so I will explain how Jackson does that.By default Jackson maps the fields of a JSON object to fields in a Java object by matching the names of the JSON field to the getter and setter methods in the Java object. Jackson removes the "get" and "set" part of the names of the getter and setter methods, and converts the first character of the remaining name to lowercase.
For instance, the JSON field named
brand
matches the Java getter and setter methods called getBrand()
and setBrand()
. The JSON field named engineNumber
would match the getter and setter named getEngineNumber()
and setEngineNumber()
.If you need to match JSON object fields to Java object fields in a different way, you need to either use a custom serializer and deserializer, or use some of the many Jackson Annotations.
Jackson Annotations
Jackson contains a set of Java annotations which you can use to modify how Jackson reads and writes JSON to and from Java objects. Jackson's annotations are explained in my Jackson annotation tutorial.Read Object From JSON String
Reading a Java object from a JSON string is pretty easy. You have actually already seen an example of how. The JSON string is passed as the first parameter to theObjectMapper
's readValue()
method. Here is another simplified example:ObjectMapper objectMapper = new ObjectMapper();
String carJson =
"{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";
Car car = objectMapper.readValue(carJson, Car.class);
Read Object From JSON Reader
You can also read an object from JSON loaded via aReader
instance. Here is an example of how to do that:ObjectMapper objectMapper = new ObjectMapper();
String carJson =
"{ \"brand\" : \"Mercedes\", \"doors\" : 4 }";
Reader reader = new StringReader(carJson);
Car car = objectMapper.readValue(reader, Car.class);
Read Object From JSON File
Reading JSON from a file can of course be done via aFileReader
(instead of a StringReader
- see previous section), but also with a File
object. Here is an example of reading JSON from a file:ObjectMapper objectMapper = new ObjectMapper();
File file = new File("data/car.json");
Car car = objectMapper.readValue(file, Car.class);
Read Object From JSON via URL
You can read an object from JSON via aURL
(java.net.URL
) like this:ObjectMapper objectMapper = new ObjectMapper();
URL url = new URL("file:data/car.json");
Car car = objectMapper.readValue(url, Car.class);
This example uses a file URL, but you can use an HTTP URL too (similar to http://jenkov.com/some-data.json
).Read Object From JSON InputStream
It is also possible to read an object from JSON via anInputStream
with the Jackson ObjectMapper
. Here is an example of reading JSON from an InputStream
:ObjectMapper objectMapper = new ObjectMapper();
InputStream input = new FileInputStream("data/car.json");
Car car = objectMapper.readValue(input, Car.class);
Read Object From JSON Byte Array
Jackson also supports reading objects from a JSONbyte
array. Here is an example of reading an object from a JSON byte
array:ObjectMapper objectMapper = new ObjectMapper();
String carJson =
"{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";
byte[] bytes = carJson.getBytes("UTF-8");
Car car = objectMapper.readValue(bytes, Car.class);
Read Object Array From JSON Array String
The JacksonObjectMapper
can also read an array of objects from a JSON array string. Here is an example of reading an object array from a JSON array string:String jsonArray = "[{\"brand\":\"ford\"}, {\"brand\":\"Fiat\"}]";
ObjectMapper objectMapper = new ObjectMapper();
Car[] cars2 = objectMapper.readValue(jsonArray, Car[].class);
Notice how the Car
array class is passed as the second parameter to the readValue()
method to tell the ObjectMapper
that you want to read an array of Car
instances.Reading arrays of objects also works with other JSON sources than a string. For instance, a file, URL,
InputStream
, Reader
etc.Read Object List From JSON Array String
The JacksonObjectMapper
can also read a Java List of objects from a JSON array string. Here is an example of reading a List
of objects from a JSON array string:String jsonArray = "[{\"brand\":\"ford\"}, {\"brand\":\"Fiat\"}]";
ObjectMapper objectMapper = new ObjectMapper();
List cars1 = objectMapper.readValue(jsonArray, new TypeReference>(){});
Notice the TypeReference
parameter passed to readValue()
. This parameter tells Jackson to read a List
of Car
objects.Ignore Unknown JSON Fields
Sometimes you have more fields in the JSON than you do in the Java object you want to read from the JSON. By default Jackson throws an exception in that case, saying that it does not know field XYZ because it is not found in the Java object.However, sometimes it should be allowed to have more fields in the JSON than in the corresponding Java object. For instance, if you are parsing JSON from a REST service which contains much more data than you need. In that case, Jackson enables you to ignore these extra fields with a Jackson configuration. Here is how configuring the Jackson
ObjectMapper
to ignore unknown fields looks:objectMapper.configure(
DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
Read Map from JSON String
The JacksonObjectMapper
can also read a Java Map from a JSON string. This can be useful if you do not know ahead of time the exact JSON structure that you will be parsing. Usually you will be reading a JSON object into a Java Map
. Each field in the JSON object will become a key, value pair in the Java Map
.Here is an example of reading a Java
Map
from a JSON String with the Jackson ObjectMapper
:String jsonObject = "{\"brand\":\"ford\", \"doors\":5}";
ObjectMapper objectMapper = new ObjectMapper();
Map jsonMap = objectMapper.readValue(jsonObject,
new TypeReference
Custom Deserializer
Sometimes you might want to read a JSON string into a Java object in a way that is different from how the JacksonObjectMapper
does this by default. You can add a custom deserializer to the ObjectMapper
which can perform the deserialization as you want it done.Here is how you register and use a custom deserializer with the Jackson
ObjectMapper
:String json = "{ \"brand\" : \"Ford\", \"doors\" : 6 }";
SimpleModule module =
new SimpleModule("CarDeserializer", new Version(3, 1, 8, null, null, null));
module.addDeserializer(Car.class, new CarDeserializer(Car.class));
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(module);
Car car = mapper.readValue(json, Car.class);
And here is how the CarDeserializer
class looks:import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import java.io.IOException;
public class CarDeserializer extends StdDeserializer {
public CarDeserializer(Class vc) {
super(vc);
}
@Override
public Car deserialize(JsonParser parser, DeserializationContext deserializer) throws IOException {
Car car = new Car();
while(!parser.isClosed()){
JsonToken jsonToken = parser.nextToken();
if(JsonToken.FIELD_NAME.equals(jsonToken)){
String fieldName = parser.getCurrentName();
System.out.println(fieldName);
jsonToken = parser.nextToken();
if("brand".equals(fieldName)){
car.setBrand(parser.getValueAsString());
} else if ("doors".equals(fieldName)){
car.setDoors(parser.getValueAsInt());
}
}
}
return car;
}
}
Write JSON From Objects
The JacksonObjectMapper
can also be used to generate JSON from an object. You do so using the one of the methods:writeValue()
writeValueAsString()
writeValueAsBytes()
Car
object, like the ones used in earlier examples:ObjectMapper objectMapper = new ObjectMapper();
Car car = new Car();
car.brand = "BMW";
car.doors = 4;
objectMapper.writeValue(
new FileOutputStream("data/output-2.json"), car);
This example first creates an ObjectMapper
, then a Car
instance, and finally calls the ObjectMapper
's writeValue()
method which converts the Car
object to JSON and writes it to the given FileOutputStream
.The
ObjectMapper
's writeValueAsString()
and writeValueAsBytes()
both generate JSON from an object, and return the generated JSON as a String
or as a byte
array. Here is an example showing how to call writeValueAsString()
:ObjectMapper objectMapper = new ObjectMapper();
Car car = new Car();
car.brand = "BMW";
car.doors = 4;
String json = objectMapper.writeValueAsString(car);
System.out.println(json);
The JSON output from this example would be:{"brand":"BMW","doors":4}
Custom Serializer
Sometimes you want to serialize a Java object to JSON differently than what Jackson does by default. For instance, you might want to use different field names in the JSON than in the Java object, or you might want to leave out certain fields altogether.Jackson enables you to set a custom serializer on the
ObjectMapper
. This serializer is registered for a certain class, and will then be called whenever the ObjectMapper
is asked to serialize a Car
object. Here is an example that shows how to register a custom serializer for the Car
class:CarSerializer carSerializer = new CarSerializer(Car.class);
ObjectMapper objectMapper = new ObjectMapper();
SimpleModule module =
new SimpleModule("CarSerializer", new Version(2, 1, 3, null, null, null));
module.addSerializer(Car.class, carSerializer);
objectMapper.registerModule(module);
Car car = new Car();
car.setBrand("Mercedes");
car.setDoors(5);
String carJson = objectMapper.writeValueAsString(car);
The string produced by this Jackson custom serializer example looks like this:{"producer":"Mercedes","doorCount":5}
The CarSerializer
class looks like this:import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import java.io.IOException;
public class CarSerializer extends StdSerializer {
protected CarSerializer(Class t) {
super(t);
}
public void serialize(Car car, JsonGenerator jsonGenerator,
SerializerProvider serializerProvider)
throws IOException {
jsonGenerator.writeStartObject();
jsonGenerator.writeStringField("producer", car.getBrand());
jsonGenerator.writeNumberField("doorCount", car.getDoors());
jsonGenerator.writeEndObject();
}
}
Notice that the second parameter passed to the serialize()
method is a Jackson JsonGeneratorinstance. You can use this instance to serialize the object - in this case a Car
object.Jackson Date Formats
By default Jackson will serialize ajava.util.Date
object to its long
value, which is the number of milliseconds since January 1st 1970. However, Jackson also supports formatting dates as strings. In this section we will take a closer look at the Jackson date formats.Date to long
First I will show you the default Jackson date format that serializes aDate
to the number of milliseconds since January 1st 1970 (its long
representation). Here is an example Java class that contains a Date
field:public class Transaction {
private String type = null;
private Date date = null;
public Transaction() {
}
public Transaction(String type, Date date) {
this.type = type;
this.date = date;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
}
Serializing a Transaction
object with the Jackson ObjectMapper
would be done just as you would serialize any other Java object. Here is how the code looks:Transaction transaction = new Transaction("transfer", new Date());
ObjectMapper objectMapper = new ObjectMapper();
String output = objectMapper.writeValueAsString(transaction);
System.out.println(output);
The output printed from this example would be similar to:{"type":"transfer","date":1516442298301}
Notice the format of the date
field: It is a long number, just as explained above.Date to String
Thelong
serialization format of a Date
is not very readable for human beings. Therefore Jackson supports a textual date format too. You specify the exact Jackson date format to use by setting a SimpleDateFormat
on the ObjectMapper
. Here is an example of setting a SimpleDateFormat
on a Jackson ObjectMapper
:SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
objectMapper2.setDateFormat(dateFormat);
String output2 = objectMapper2.writeValueAsString(transaction);
System.out.println(output2);
The output printed from this example would look similar to this:{"type":"transfer","date":"2018-01-20"}
Notice how the date
field is now formatted as a String.Jackson JSON Tree Model
Jackson has a built-in tree model which can be used to represent a JSON object. Jackson's tree model is useful if you don't know how the JSON you will receive looks, or if you for some reason cannot (or just don't want to) create a class to represent it.The Jackson tree model is represented by the
JsonNode
class. You use the Jackson ObjectMapper
to parse JSON into a JsonNode
tree model, just like you would have done with your own class.Jackson Tree Model Example
Here is a simple Jackson tree model example:String carJson =
"{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";
ObjectMapper objectMapper = new ObjectMapper();
try {
JsonNode node = objectMapper.readValue(carJson, JsonNode.class);
} catch (IOException e) {
e.printStackTrace();
}
As you can see, the JSON string is parsed into a JsonNode
object instead of a Car
object, simply by passing the JsonNode.class
as second parameter to the readValue()
method instead of the Car.class
used in the example earlier in this tutorial.The Jackson JsonNode Class
Once you have parsed your JSON into aJsonNode
(or a tree of JsonNode
instances) you can navigate the JsonNode
tree model. Here is a JsonNode
example that shows how to access JSON fields, arrays and nested objects:String carJson =
"{ \"brand\" : \"Mercedes\", \"doors\" : 5," +
" \"owners\" : [\"John\", \"Jack\", \"Jill\"]," +
" \"nestedObject\" : { \"field\" : \"value\" } }";
ObjectMapper objectMapper = new ObjectMapper();
try {
JsonNode node = objectMapper.readValue(carJson, JsonNode.class);
JsonNode brandNode = node.get("brand");
String brand = brandNode.asText();
System.out.println("brand = " + brand);
JsonNode doorsNode = node.get("doors");
int doors = doorsNode.asInt();
System.out.println("doors = " + doors);
JsonNode array = node.get("owners");
JsonNode jsonNode = array.get(0);
String john = jsonNode.asText();
System.out.println("john = " + john);
JsonNode child = node.get("nestedObject");
JsonNode childField = child.get("field");
String field = childField.asText();
System.out.println("field = " + field);
} catch (IOException e) {
e.printStackTrace();
}
Notice that the JSON string now contains an array field called owners
and a nested object field called nestedObject
.Regardless of whether you are accessing a field, array or nested object you use the
get()
method of the JsonNode
class. By providing a string as parameter to the get()
method you can access a field of a JsonNode
. If the JsonNode
represents an array, you need to pass an index to the get()
method instead. The index specifies what element in the array you want to get.This concludes this Jackson ObjectMapper tutorial. I hope you found this tutorial useful!
Jackson Annotations
The Jackson JSON toolkit contains a set of Java annotations which you can use to influence how JSON is read into objects, or what JSON is generated from the objects. This Jackson annotation tutorial explains how to use Jackson's annotations.
If you are unfamiliar with Java annotations, read my Java annotation tutorial before reading this tutorial. It will help you understand how Java annotations work.
The following
The
You can tell Jackson to call the
Keep in mind that this only has effect on unrecognized fields. If, for instance, you added a public
The
To mark a field in a Java class as a field that needs to have its value injected by Jackson, add the
If you were to download person JSON objects from multiple sources and have a different source value injected for each source, you would have to repeat the above code for each source.
First you would need to add the
You obtain the value of the field to deserialize by calling the
Finally you need to see what it looks like to deserialize an object with a custom deserializer and the
A more saying name for the
Here is an example class named
To make it more clear what
Well, if the
Without the
The
The
If you are unfamiliar with Java annotations, read my Java annotation tutorial before reading this tutorial. It will help you understand how Java annotations work.
Read + Write Annotations
Jackson contains a set of annotations that affect both the reading of Java objects from JSON, as well as the writing of Java objects into JSON. I refer to these annotations as "read + write annotations". The following sections explain Jackson's read + write annotations in more detail.@JsonIgnore
The Jackson annotation@JsonIgnore
is used to tell Jackson to ignore a certain property (field) of a Java object. The property is ignored both when reading JSON into Java objects, and when writing Java objects into JSON. Here is an example class that uses the @JsonIgnore
annotation:import com.fasterxml.jackson.annotation.JsonIgnore;
public class PersonIgnore {
@JsonIgnore
public long personId = 0;
public String name = null;
}
In the above class the property personId
will not be read from JSON or written to JSON.@JsonIgnoreProperties
The@JsonIgnoreProperties
Jackson annotation is used to specify a list of properties of a class to ignore. The @JsonIgnoreProperties
annotation is placed above the class declaration instead of above the individual properties (fields) to ignore. Here is an example showing how to use the @JsonIgnoreProperties
annotation:import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@JsonIgnoreProperties({"firstName", "lastName"})
public class PersonIgnoreProperties {
public long personId = 0;
public String firstName = null;
public String lastName = null;
}
In this example both the properties firstName
and lastName
will be ignored because their names are listed inside the @JsonIgnoreProperties
annotation declaration above the class declaration.@JsonIgnoreType
The@JsonIgnoreType
Jackson annotation is used to mark a whole type (class) to be ignored everywhere that type is used. Here is an example that shows you how you could use the @JsonIgnoreType
annotation:import com.fasterxml.jackson.annotation.JsonIgnoreType;
public class PersonIgnoreType {
@JsonIgnoreType
public static class Address {
public String streetName = null;
public String houseNumber = null;
public String zipCode = null;
public String city = null;
public String country = null;
}
public long personId = 0;
public String name = null;
public Address address = null;
}
In the above example all Address
instances will be ignored.@JsonAutoDetect
The Jackson annotation@JsonAutoDetect
is used to tell Jackson to include properties which are not public, both when reading and writing objects. Here is an example class showing you how you can use the@JsonAutoDetect
annotation:import com.fasterxml.jackson.annotation.JsonAutoDetect;
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY )
public class PersonAutoDetect {
private long personId = 123;
public String name = null;
}
The JsonAutoDetect.Visibility
class contains constants matching the visibility levels in Java, meaning ANY
, DEFAULT
, NON_PRIVATE
, NONE
, PROTECTED_AND_PRIVATE
and PUBLIC_ONLY
.Read Annotations
Jackson contains a set of annotations that only affect how Jackson parses JSON into objects - meaning they affect Jackson's reading of JSON. I refer to these as "read annotations". The following sections explains Jackson's read annotations.@JsonSetter
The Jackson annotation@JsonSetter
is used to tell Jackson that is should match the name of this setter method to a property name in the JSON data, when reading JSON into objects. This is useful if the property names used internally in your Java class is not the same as the property name used in the JSON file.The following
Person
class uses the name personId
for its id property:public class Person {
private long personId = 0;
private String name = null;
public long getPersonId() { return this.personId; }
public void setPersonId(long personId) { this.personId = personId; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
But in this JSON object the name id
is used instead of personId
:{
"id" : 1234,
"name" : "John"
}
Without some help Jackson cannot map the id
property from the JSON object to the personId
field of the Java class.The
@JsonSetter
annotation instructs Jackson to use a setter method for a given JSON field. In our case we add the @JsonSetter
annotation above the setPersonId()
method. Here is how adding the @JsonSetter
annotation looks like:public class Person {
private long personId = 0;
private String name = null;
public long getPersonId() { return this.personId; }
@JsonSetter("id")
public void setPersonId(long personId) { this.personId = personId; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
The value specified inside the @JsonSetter
annotation is the name of the JSON field to match to this setter method. In this case the name is id
since that is the name of the field in the JSON object we want to map to the setPersonId()
setter method.@JsonAnySetter
The Jackson annotation@JsonAnySetter
instructs Jackson to call the same setter method for all unrecognized fields in the JSON object. By "unrecognized" I mean all fields that are not already mapped to a property or setter method in the Java object. Look at this Bag
class:public class Bag {
private Map properties = new HashMap<>();
public void set(String fieldName, Object value){
this.properties.put(fieldName, value);
}
public Object get(String fieldName){
return this.properties.get(fieldName);
}
}
And then look at this JSON object:{
"id" : 1234,
"name" : "John"
}
Jackson cannot directly map the id
and name
property of this JSON object to the Bag
class, because the Bag
class contains no public fields or setter methods.You can tell Jackson to call the
set()
method for all unrecognized fields by adding the @JsonAnySetter
annotation, like this:public class Bag {
private Map properties = new HashMap<>();
@JsonAnySetter
public void set(String fieldName, Object value){
this.properties.put(fieldName, value);
}
public Object get(String fieldName){
return this.properties.get(fieldName);
}
}
Now Jackson will call the set()
method with the name and value of all unrecognized fields in the JSON object.Keep in mind that this only has effect on unrecognized fields. If, for instance, you added a public
name
property or setName(String)
method to the Bag
Java class, then the name
field in the JSON object would be mapped to that property / setter instead.@JsonCreator
The Jackson annotation@JsonCreator
is used to tell Jackson that the Java object has a constructor (a "creator") which can match the fields of a JSON object to the fields of the Java object.The
@JsonCreator
annotation is useful in situations where the @JsonSetter
annotation cannot be used. For instance, immutable objects do not have any setter methods, so they need their initial values injected into the constructor. Look at this PersonImmutable
class as example:public class PersonImmutable {
private long id = 0;
private String name = null;
public PersonImmutable(long id, String name) {
this.id = id;
this.name = name;
}
public long getId() {
return id;
}
public String getName() {
return name;
}
}
To tell Jackson that it should call the constructor of PersonImmutable
we must add the @JsonCreator
annotation to the constructor. But that alone is not enough. We must also annotate the parameters of the constructor to tell Jackson which fields from the JSON object to pass to which constructor parameters. Here is how the PersonImmutable
class looks with the @JsonCreator
and @JsonProperty
annotations added:public class PersonImmutable {
private long id = 0;
private String name = null;
@JsonCreator
public PersonImmutable(
@JsonProperty("id") long id,
@JsonProperty("name") String name ) {
this.id = id;
this.name = name;
}
public long getId() {
return id;
}
public String getName() {
return name;
}
}
Notice the annotation above the constructor and the annotations before the constructor parameters. Now Jackson is capable of creating a PersonImmutable
from this JSON object:{
"id" : 1234,
"name" : "John"
}
@JacksonInject
The Jackson annotation@JacksonInject
is used to inject values into the parsed objects, instead of reading those values from the JSON. For instance, imagine you are downloading person JSON objects from various different sources, and would like to know what source a given person object came from. The sources may not themselves contain that information, but you can have Jackson inject that into the Java objects created from the JSON objects.To mark a field in a Java class as a field that needs to have its value injected by Jackson, add the
@JacksonInject
annotation above the field. Here is an example PersonInject
class with the @JacksonInject
annotation added above the source
field:public class PersonInject {
public long id = 0;
public String name = null;
@JacksonInject
public String source = null;
}
In order to have Jackson inject values into the source
field you need to do a little extra when creating the Jackson ObjectMapper
. Here is what it takes to have Jackson inject values into the Java objects:InjectableValues inject = new InjectableValues.Std().addValue(String.class, "jenkov.com");
PersonInject personInject = new ObjectMapper().reader(inject)
.forType(PersonInject.class)
.readValue(new File("data/person.json"));
Notice how the value to inject into the source
attribute is set in the InjectableValues
addValue()
method. Notice also that the value is only tied to the type String
- not to any specific field name. It is the @JacksonInject
annotation that specifies what field the value is to be injected into.If you were to download person JSON objects from multiple sources and have a different source value injected for each source, you would have to repeat the above code for each source.
@JsonDeserialize
The Jackson annotation@JsonDeserialize
is used to specify a custom de-serializer class for a given field in a Java object. For instance, imagine you wanted to optimize the on-the-wire formatting of the boolean values false
and true
to 0
and 1
.First you would need to add the
@JsonDeserialize
annotation to the field you want to use the custom deserializer for. Here is how adding the @JsonDeserialize
annotation to a field looks like:public class PersonDeserialize {
public long id = 0;
public String name = null;
@JsonDeserialize(using = OptimizedBooleanDeserializer.class)
public boolean enabled = false;
}
Second, here is what the OptimizedBooleanDeserializer
class referenced from the @JsonDeserialize
annotation looks like:public class OptimizedBooleanDeserializer
extends JsonDeserializer {
@Override
public Boolean deserialize(JsonParser jsonParser,
DeserializationContext deserializationContext) throws
IOException, JsonProcessingException {
String text = jsonParser.getText();
if("0".equals(text)) return false;
return true;
}
}
Notice that the OptimizedBooleanDeserializer
class extends JsonDeserializer
with the generic type Boolean
. Doing so makes the deserialize()
method return a Boolean
object. If you were to deserialize another type (e.g a java.util.Date
) you would have to specify that type inside the generics brackets (if you are new to Java generics, I have a Java Generics Tutorial too).You obtain the value of the field to deserialize by calling the
getText()
method of the jsonParser
parameter. You can then deserialize that text into whatever value and type your deserializer is targeted at (a Boolean
in this example).Finally you need to see what it looks like to deserialize an object with a custom deserializer and the
@JsonDeserializer
annotation:PersonDeserialize person = objectMapper
.reader(PersonDeserialize.class)
.readValue(new File("data/person-optimized-boolean.json"));
Notice how we first need to create a reader for the PersonDeserialize
class using the ObjectMapper
's reader()
method, and then we call readValue()
on the object returned by that method.Write Annotations
Jackson also contains a set of annotations that can influence how Jackson serializes (writes) Java objects to JSON. Each of these write (serialization) annotations will be covered in the following sections.@JsonInclude
The Jackson annotation@JsonInclude
tells Jackson only to include properties under certain circumstances. For instance, that properties should only be included if they are non-null, non-empty, or have non-default values. Here is an example that shows how you can use the @JsonInclude
annotation:import com.fasterxml.jackson.annotation.JsonInclude;
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class PersonInclude {
public long personId = 0;
public String name = null;
}
This example will only include the name
property if the value set for it is non-empty, meaning is not null and is not an empty string.A more saying name for the
@JsonInclude
annotation could have been @JsonIncludeOnlyWhen
, but that would have been longer to write.@JsonGetter
The@JsonGetter
Jackson annotation is used to tell Jackson that a certain field value should be obtained from calling a getter
method instead of via direct field access. The @JsonGetter
annotation is useful if your Java class uses jQuery style for getter and setter names. For instance, instead of getPersonId()
and setPersonId()
you might have the methods personId()
and personId(long id)
.Here is an example class named
PersonGetter
which shows the use of the @JsonGetter
annotation:public class PersonGetter {
private long personId = 0;
@JsonGetter("id")
public long personId() { return this.personId; }
@JsonSetter("id")
public void personId(long personId) { this.personId = personId; }
}
As you can see, the personId()
method is annotated with the @JsonGetter
annotation. The value set on the @JsonGetter
annotation is the name that should be used in the JSON object. Thus, the name used for the personId
in the JSON object is id
. The resulting JSON object would look like this:{"id":0}
Notice also that the personId(long personId)
method is annotated with the @JsonSetter
annotation to make Jackson recognized that as the setter matching the id
attribute in the JSON object. The @JsonSetter
annotation is used when reading from JSON into Java objects - not when writing Java objects to JSON. The @JsonSetter
annotation is just included for the sake of completeness.@JsonAnyGetter
The@JsonAnyGetter
Jackson annotation enables you to use a Map
as container for properties that you want to serialize to JSON. Here is an example of using the @JsonAnyGetter
annotation in a Java class:public class PersonAnyGetter {
private Map properties = new HashMap<>();
@JsonAnyGetter
public Map properties() {
return properties;
}
}
When seeing the @JsonAnyGetter
annotation Jackson will obtain the Map
returned from the method which @JsonAnyGetter
annotates, and will treat each key-value pair in that Map
as a property. In other words, all key-value pairs in the Map
will be serialized to JSON as part of the PersonAnyGetter
object.@JsonPropertyOrder
The@JsonPropertyOrder
Jackson annotation can be used to specify in what order the fields of your Java object should be serialized into JSON. Here is an example showing how to use the @JsonPropertyOrder
annotation:@JsonPropertyOrder({"name", "personId"})
public class PersonPropertyOrder {
public long personId = 0;
public String name = null;
}
Normally Jackson would have serialized the properties in PersonPropertyOrder
in the sequence they are found in the class. However, the @JsonPropertyOrder
annotation specifies a different order where the name
property will be appear first and the personId
property second in the serialized JSON output.@JsonRawValue
The@JsonRawValue
Jackson annotation tells Jackson that this property value should written directly as it is to the JSON output. If the property is a String
Jackson would normally have enclosed the value in quotation marks, but if annotated with the @JsonRawValue
property Jackson won't do that.To make it more clear what
@JsonRawValue
does, look at this class without the @JsonRawValue
in use:public class PersonRawValue {
public long personId = 0;
public String address = "$#";
}
Jackson would serialize this into this JSON string:{"personId":0,"address":"$#"}
Now we add the @JsonRawValue
to the address
property, like this:public class PersonRawValue {
public long personId = 0;
@JsonRawValue
public String address = "$#";
}
Jackson will now omit the quotation marks when serializing the address
property. The serialized JSON will thus look like this:{"personId":0,"address":$#}
This is of course invalid JSON, so why would you want that?Well, if the
address
property contained a JSON string then that JSON string would be serialized into the final JSON object as part of the JSON object structure, and not just into a string in the address
field in the JSON object. To see how that would work, let us change the value of the address
property like this:public class PersonRawValue {
public long personId = 0;
@JsonRawValue
public String address =
"{ \"street\" : \"Wall Street\", \"no\":1}";
}
Jackson would serialize this into this JSON:{"personId":0,"address":{ "street" : "Wall Street", "no":1}}
Notice how the JSON string is now part of the serialized JSON structure.Without the
@JsonRawValue
annotation Jackson would have serialized the object to this JSON:{"personId":0,"address":"{ \"street\" : \"Wall Street\", \"no\":1}"}
Notice how the value of the address
property is now enclosed in quotation marks, and all the quotation marks inside the value are escaped.@JsonValue
The Jackson annotation@JsonValue
tells Jackson that Jackson should not attempt to serialize the object itself, but rather call a method on the object which serializes the object to a JSON string. Note that Jackson will escape any quotation marks inside the String returned by the custom serialization, so you cannot return e.g. a full JSON object. For that you should use @JsonRawValue
instead (see previous section).The
@JsonValue
annotation is added to the method that Jackson is to call to serialize the object into a JSON string. Here is an example showing how to use the @JsonValue
annotation:public class PersonValue {
public long personId = 0;
public String name = null;
@JsonValue
public String toJson(){
return this.personId + "," + this.name;
}
}
The output you would get from asking Jackson to serialize a PersonValue
object is this:"0,null"
The quotation marks are added by Jackson. Remember, any quotation marks in the value string returned by the object are escaped.@JsonSerialize
The@JsonSerialize
Jackson annotation is used to specify a custom serializer for a field in a Java object. Here is an example Java class that uses the @JsonSerialize
annotation:public class PersonSerializer {
public long personId = 0;
public String name = "John";
@JsonSerialize(using = OptimizedBooleanSerializer.class)
public boolean enabled = false;
}
Notice the @JsonSerialize
annotation above the enabled
field.The
OptimizedBooleanSerializer
will serialize a true
value to 1
and a false
value 0
. Here is the code:public class OptimizedBooleanSerializer extends JsonSerializer {
@Override
public void serialize(Boolean aBoolean, JsonGenerator jsonGenerator,
SerializerProvider serializerProvider)
throws IOException, JsonProcessingException {
if(aBoolean){
jsonGenerator.writeNumber(1);
} else {
jsonGenerator.writeNumber(0);
}
}
}
Nice article. you explain topics in good way. thanks for sharing good post. there is also good json resource visit
ReplyDeletejson tutorials
To parse the Json in java we use jsonparser. To use jsonparser in java we have to add below dependency in our pom.xml file.
ReplyDeletecom.googlecode.json-simple
json-simple
1.1.1
Now suppose you have to parse the below complex json.
{
"name": "vasu",
"age": 26,
"email": "vasu@gmail.com",
"educationDetail": {
"college": "GEHU Dehradun",
"course": "B.Tech",
"Branch": "CSE"
},
"matrixEducation": [{
"10ClassBoard": "Pass 10 class from UP Board"
}, {
"12ClassBoard": "pass 12 class from UP Board"
}]
}
So for this we create a JsonParser and make below code to parse data using this parser.
private JSONParser parser = new JSONParser();
JSONObject jObj = (JSONObject) parser.parse(payload);
String name = jObj.get("name").toString();
String age = jObj.get("age").toString();
String email = jObj.get("email").toString();
JSONObject educationObj = (JSONObject) jObj.get("educationDetail");
String collegeName = educationObj.get("college").toString();
String course = educationObj.get("course").toString();
String branch = educationObj.get("Branch").toString();
JSONArray matrixDetail = (JSONArray) jObj.get("matrixEducation");
JSONObject highSchoolObj = (JSONObject)matrixDetail.get(0);
String highSchoolboard = highSchoolObj.get("10ClassBoard").toString();
JSONObject interSchoolObj = (JSONObject)matrixDetail.get(1);
String interSchoolboard = interSchoolObj.get("12ClassBoard").toString();
Checkout complete example on jsonparser on below URL
https://www.javadream.in/jsonparser-in-java/