DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
  1. DZone
  2. Coding
  3. Languages
  4. Jackson Annotations for JSON (Part 3): Deserialization

Jackson Annotations for JSON (Part 3): Deserialization

As we continue our journey through Jackson annotations, let's see what you can use to help control deserialization of JSON into POJOs.

John Thompson user avatar by
John Thompson
·
Dec. 25, 17 · Tutorial
Like (10)
Save
Tweet
Share
159.98K Views

Join the DZone community and get the full member experience.

Join For Free

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

  • Streaming (jackson-core) defines low-level streaming APIs and includes JSON-specific implementations.

  • Annotations (jackson-annotations) contains standard Jackson annotations.

  • Databind (jackson-databind) implements data-binding (and object serialization) support on the streaming package. This package depends on both the streaming and annotations packages.

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

If you want to catch up on what's happened so far, read:

  • Part 1: Serialization and Deserialization

  • Part 2: Serialization

Deserialization Annotations

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

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

@JsonSetter

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

A Java class that uses the @JsonSetter annotation is:

SetterDemoBean.java

package guru.springframework.blog.jsonannotation.domain.deserialization;

import com.fasterxml.jackson.annotation.JsonSetter;

public class SetterDemoBean {
    public long personId = 0;
    public String  name = "James Clark";
    @JsonSetter("id")
    public void setPersonId(long personId) {
        this.personId = personId;
    }
    @Override
    public String toString() {
        return "SetterDemoBean{" +
                "personId=" + personId +
                ", name='" + name + '\'' +
                '}';
    }
}


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

The test code to test the @JsonSetter annotation is:

@Test
public void testDeSerializingWithJsonSetter() throws IOException {
    String jsonString = "{\"id\": 231, \"name\": \"Mary Parker\"}";
    ObjectMapper mapper = new ObjectMapper();
    SetterDemoBean bean = objectMapper.readValue(jsonString, SetterDemoBean.class);
    System.out.println(bean);
    assertThat(bean.name, is(equalTo("Mary Parker")));
    assertThat(bean.personId, is(equalTo(231L)));
}


The output of running the test in IntelliJ is:

@JsonSetter Test Output

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

@JsonAnySetter

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

A Java class that uses the @JsonAnySetter annotation is:

AnySetterDemoBean.java

package guru.springframework.blog.jsonannotation.domain.deserialization;

import com.fasterxml.jackson.annotation.JsonAnySetter;

import java.util.HashMap;
import java.util.Map;

public class AnySetterDemoBean {
    public long personId = 123L;
    public String  personName = "James Clark";
    private Map<String, String> properties = new HashMap<String, String>();

    @JsonAnySetter
    public void setProperties(String key, String value){
        properties.put(key, value);
    }

    @Override
    public String toString() {
        return "AnySetterDemoBean{" +
                "personId=" + personId +
                ", personName='" + personName + '\'' +
                ", properties=" + properties +
                '}';
    }
}


The test code to test the @JsonAnySetter annotation is:

@Test
public void testDeSerializingWithJsonSetter() throws IOException {
    String jsonString = "{\"personId\": 231, \"personName\": \"Mary Parker\", \"emailId\": \"mary@gmail.com\", \"gender\": \"female\"}";
    ObjectMapper mapper = new ObjectMapper();
    AnySetterDemoBean bean = objectMapper.readValue(jsonString, AnySetterDemoBean.class);
    System.out.println(bean);
    assertThat(bean.personName, is(equalTo("Mary Parker")));
    assertThat(bean.personId, is(equalTo(231L)));
   assertEquals("female", bean.getProperties().get("gender"));
}


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

@JsonCreator

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

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

CreatorDemoBean.java

package guru.springframework.blog.jsonannotation.domain.deserialization;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;

public class CreatorDemoBean {
    public long personId = 0;
    public String  name = "James Clark";

    @JsonCreator
    public CreatorDemoBean(@JsonProperty("id") long personId, @JsonProperty("name") String name) {
        this.personId = personId;
        this.name = name;
    }

    @Override
    public String toString() {
        return "CreatorDemoBean{" +
                "personId=" + personId +
                ", name='" + name + '\'' +
                '}';
    }
}


The test code to test the @JsonCreator annotation is:

@Test
public void testDeSerializingWithJsonCreator() throws IOException {
    String jsonString = "{\"id\": 231, \"name\": \"Mary Parker\"}";
    ObjectMapper mapper = new ObjectMapper();
    CreatorDemoBean bean = objectMapper.readValue(jsonString, CreatorDemoBean.class);
    System.out.println(bean);
    assertThat(bean.name, is(equalTo("Mary Parker")));
    assertThat(bean.personId, is(equalTo(231L)));
}


The output of running the test in IntelliJ is this.

@JacksonInject

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

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

JacksonInjectDemoBean.java

package guru.springframework.blog.jsonannotation.domain.deserialization;

import com.fasterxml.jackson.annotation.JacksonInject;

public class JacksonInjectDemoBean {
    @JacksonInject
    public long personId = 0;
    public String  name = "James Clark";

    @Override
    public String toString() {
        return "JacksonInjectDemoBean{" +
                "personId=" + personId +
                ", name='" + name + '\'' +
                '}';
    }
}


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

The test code to test the @JacksonInject annotation is:

@Test
public void testDeSerializingWithJacksonInject() throws IOException {
    String jsonString = "{\"name\": \"Mary Parker\"}";
    InjectableValues injectableValues = new InjectableValues.Std()
        .addValue(long.class, 231L);
    JacksonInjectDemoBean bean = new ObjectMapper().reader(injectableValues)
        .forType(JacksonInjectDemoBean.class).readValue(jsonString);
    System.out.println(bean);
    assertThat(bean.name, is(equalTo("Mary Parker")));
    assertThat(bean.personId, is(equalTo(231L)));
}


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

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

@JsonDeserialize

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

A Java class that uses the @JsonDeserialize annotation is:

DeserializeDemoBean.java

package guru.springframework.blog.jsonannotation.domain.deserialization;

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import guru.springframework.blog.jsonannotation.domain.custom.CustomDateDeserializer;

import java.util.Date;

public class DeserializeDemoBean {
    public long personId = 123L;
    public String  name = "James Clark";
    @JsonDeserialize(using = CustomDateDeserializer.class)
    public Date activeDate;

    @Override
    public String toString() {
        return "DeserializeDemoBean{" +
                "personId=" + personId +
                ", name='" + name + '\'' +
                ", activeDate=" + activeDate +
                '}';
    }
}


The custom deserializer that is referenced by the preceding DeserializeDemoBeanbean class is:

CustomDateDeserializer.java

package guru.springframework.blog.jsonannotation.domain.custom;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import java.text.ParseException;

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

public class CustomDateDeserializer extends StdDeserializer<Date> {

    private static SimpleDateFormat simpleDateFormat =
            new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");

    public CustomDateDeserializer(){
        this(null);
    }
    public CustomDateDeserializer(Class<?> c){
        super(c);
    }

    @Override
    public Date deserialize(JsonParser jsonParser, DeserializationContext
            deserializationContext) throws IOException, JsonProcessingException {
        String date = jsonParser.getText();
        try {
            return simpleDateFormat.parse(date);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }
}


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

The test code to test the @JsonDeserialize annotation is:

@Test
public void testDeSerializingWithJsonDeserialize() throws IOException {
    String jsonString = "{\"personId\": 231, \"name\": \"Mary Parker\", " +
          "\"activeDate\":\"26-09-2017 11:00:00\"}";
    SimpleDateFormat simpleDateFormat =
          new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");
    ObjectMapper mapper = new ObjectMapper();
    DeserializeDemoBean bean = objectMapper.readValue(jsonString, DeserializeDemoBean.class);
    System.out.println(bean);
    assertThat(bean.name, is(equalTo("Mary Parker")));
    assertThat(bean.personId, is(equalTo(231L)));
    assertEquals("26-09-2017 11:00:00", simpleDateFormat.format(bean.activeDate));
}


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


JSON Annotation Jackson (API)

Published at DZone with permission of John Thompson, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Choosing the Right Framework for Your Project
  • Introduction to Container Orchestration
  • Building a RESTful API With AWS Lambda and Express
  • Using GPT-3 in Our Applications

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: