Java JSON Tutorial

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:
  • Jackson Core
  • Jackson Annotations
  • Jackson Databind
These projects use each other in that sequence too. Jackson Annotation uses the Jackson Core features, and the Jackson Databind uses Jackson Annotation.
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-corejackson-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 (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

The ObjectMapper 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 Jackson ObjectMapper 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 the ObjectMapper'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 a Reader 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 a FileReader (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 a URL (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 an InputStream 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 JSON byte 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 Jackson ObjectMapper 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,InputStreamReader etc.

Read Object List From JSON Array String

The Jackson ObjectMapper 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 Listof 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 Jackson ObjectMapper 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 Jackson ObjectMapper 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 Jackson ObjectMapper can also be used to generate JSON from an object. You do so using the one of the methods:
  • writeValue()
  • writeValueAsString()
  • writeValueAsBytes()
Here is an example of generating JSON from a 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 a java.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 a Date 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

The long 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 SimpleDateFormaton 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.classused in the example earlier in this tutorial.

The Jackson JsonNode Class

Once you have parsed your JSON into a JsonNode (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.

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 @JsonIgnorePropertiesannotation:
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 ANYDEFAULTNON_PRIVATENONEPROTECTED_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 @JsonSetterannotation 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 @JsonAnySetterannotation, 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 nameproperty 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 @JsonCreatorannotation 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 @JsonDeserializeannotation 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 jsonParserparameter. 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 @JsonSetterannotation 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 @JsonPropertyOrderannotation:
@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 nameproperty 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);
        }
    }
}

Comments

  1. Nice article. you explain topics in good way. thanks for sharing good post. there is also good json resource visit
    json tutorials

    ReplyDelete
  2. 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.


    com.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/

    ReplyDelete

Post a Comment