Jackson Custom Deserializer

By Arvind Rai, April 09, 2019
Jackson provides JsonDeserializer and its subclasses such as StdDeserializer to deserialize objects from JSON. According to Jackson, we should extend StdDeserializer or its subtypes like StdScalarDeserializer class to create custom deserializer instead of using JsonDeserializer abstract class. Here on this page we will provide custom deserializer example using StdDeserializer class. For custom deserialization, we need to do following below steps.
1. Create a class extending StdDeserializer and then override its deserialize() method.
2. Register the custom deserializer with ObjectMapper.
3. Or use @JsonDeserialize annotation.

Now find the complete example to create custom deserializer and use it step-by-step.

Technologies Used

Find the technologies being used in our example.
1. Java 11
2. Jackson 2.9.8
3. Gradle 4.3.1

Gradle File

Find the Gradle file used in our example.
build.gradle
apply plugin: 'java'
apply plugin: 'eclipse'
archivesBaseName = 'concretepage'
version = '0.0.1-SNAPSHOT' 
repositories {
    mavenCentral()
}
dependencies {
    compile group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.9.8'
    compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.9.8'
    compile group: 'com.fasterxml.jackson.core', name: 'jackson-annotations', version: '2.9.8'
} 

1. Create a Class extending StdDeserializer

StdDeserializer is the base class to create common deserializers. To create a custom deserializer, we need to create a class extending StdDeserializer and then override its deserialize() method. We can use custom deserializer either by registering with ObjectMapper or annotating class with @JsonDeserialize.
Now find the JSON used in our demo.
{
  "compId" : 100,
  "compName" : "ABC Ltd",
  "compAddress" : {
    "city" : "Varanasi",
    "country" : "India"
  }
} 
We will create custom deserializer for the above JSON as following.
MyCustomDeserializer.java
package com.concretepage;
import java.io.IOException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.TreeNode;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
public class MyCustomDeserializer extends StdDeserializer<Company> {
  private static final long serialVersionUID = 1L;

  public MyCustomDeserializer() {
	this(Company.class);
  }

  protected MyCustomDeserializer(Class<?> vc) {
	super(vc);
  }

  @Override
  public Company deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
	TreeNode tn = p.readValueAsTree();
	Integer compId;
	String compName;
	String city;
	String country;

	if (tn.get("compId") != null) {
	  compId = Integer.parseInt(tn.get("compId").toString());
	} else {
	  compId = 000;
	}

	if (tn.get("compName") != null) {
	  compName = tn.get("compName").toString() + "-Modified";
	} else {
	  compName = "NA";
	}

	if (tn.get("compAddress") != null && tn.get("compAddress").get("city") != null) {
	  city = tn.get("compAddress").get("city").toString() + "-Modified";
	} else {
	  city = "NA";
	}

	if (tn.get("compAddress") != null && tn.get("compAddress").get("country") != null) {
	  country = tn.get("compAddress").get("country").toString() + "-Modified";
	} else {
	  country = "NA";
	}
	Address address = new Address(city, country);
	return new Company(compId, compName, address);
  }
} 
deserialize() method has following arguments.
JsonParser: Reads JSON content.
DeserializationContext: Context for the process of deserialization a single root-level value.

We can iterate JSON property as following. Here p is the instance of JsonParser in deserialize() method.
TreeNode tn = p.readValueAsTree();
Iterator<String> compFields = tn.fieldNames();
while(compFields.hasNext()) {
  String field = compFields.next();
  System.out.println(field);
  System.out.println(tn.get(field));
}
System.out.println("-------------------");
Iterator<String> addressFields = tn.get("compAddress").fieldNames();  
while(addressFields.hasNext()) {
  String field = addressFields.next();
  System.out.println(field);
  System.out.println(tn.get("compAddress").get(field));
} 
Find the code for Address and Company classes.
Address.java
package com.concretepage;
import com.fasterxml.jackson.annotation.JsonProperty;
public class Address {
  @JsonProperty("city")
  private String city;

  @JsonProperty("country")
  private String country;

  public Address() {
  }
  public Address(String city, String country) {
	this.city = city;
	this.country = country;
  }
  public String getCity() {
	return city;
  }
  public String getCountry() {
	return country;
  }
  @Override
  public String toString() {
	return city + " | " + country;
  }
} 
Company.java
package com.concretepage;
import com.fasterxml.jackson.annotation.JsonProperty;
public class Company {
  @JsonProperty("compId")
  private Integer id;

  @JsonProperty("compName")
  private String name;

  @JsonProperty("compAddress")
  private Address address;

  public Company() {
  }

  public Company(Integer id, String name, Address address) {
	this.id = id;
	this.name = name;
	this.address = address;
  }
  public Integer getId() {
	return id;
  }
  public String getName() {
	return name;
  }
  public Address getAddress() {
	return address;
  }

  @Override
  public String toString() {
	return id + " | " + name;
  }
}

2. Register Custom Deserializer with ObjectMapper

To register custom deserializer with ObjectMapper, Jackson provides SimpleModule.addDeserializer() for specified type. Find the code snippet.
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(Company.class, new MyCustomDeserializer());
mapper.registerModule(module); 
Find the example.
DeserializeDemo.java
package com.concretepage;
import java.io.IOException;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
public class DeserializeDemo {
  public static void main(String[] args) throws JsonParseException, JsonMappingException, IOException {
	 String jsonData = 
	   "{"
		  + "\"compId\" : 100,"
		  + "\"compName\" : \"ABC Ltd\","
		  + "\"compAddress\" : {"
		  +   "\"city\" : \"Varanasi\","
		  +   "\"country\" : \"India\""
		  + "}"
	   +"}";

	 ObjectMapper mapper = new ObjectMapper();
	 SimpleModule module = new SimpleModule();
	 module.addDeserializer(Company.class, new MyCustomDeserializer());
	 mapper.registerModule(module);	 
	 
	 Company company = mapper.readValue(jsonData, Company.class);
	 System.out.println(company);
	 System.out.println(company.getAddress());
  }
}
Output
100 | "ABC Ltd"-Modified
"Varanasi"-Modified | "India"-Modified 

3. Register Custom Deserializer with @JsonDeserialize

We can register custom deserializer using @JsonDeserialize annotation by attaching to "setter" methods or fields, or to value classes. It has attributes such as using, as, keyAs, contentAs etc. using attribute specifies the custom deserializer class.
Here in our example, we will attach custom deserializer at class level. Find the example.
Company.java
package com.concretepage;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;

@JsonDeserialize(using= MyCustomDeserializer.class)
public class Company {
  @JsonProperty("compId")
  private Integer id;

  @JsonProperty("compName")
  private String name;

  @JsonProperty("compAddress")
  private Address address;

  // 
} 
Now use ObjectMapper as following.
ObjectMapper mapper = new ObjectMapper();
 
Company company = mapper.readValue(jsonData, Company.class);
System.out.println(company);
System.out.println(company.getAddress()); 

References

Class JsonDeserializer
Class StdDeserializer
@JsonDeserialize
POSTED BY
ARVIND RAI
ARVIND RAI
LEARN MORE








©2024 concretepage.com | Privacy Policy | Contact Us