Jackson Custom Deserializer
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.
Contents
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" } }
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)); }
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; } }
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 withObjectMapper
, 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);
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()); } }
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; // }
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 JsonDeserializerClass StdDeserializer
@JsonDeserialize