Ads Top

Jackson Custom Deserializer

Jackson custom deserializer

Overview:

Jackson object mapper provides the ability to read and write JSON, either to and from POJO's. It performs the conversion for us, which most of the time works fine, but sometimes we need custom deserializer in some cases where we want to deserialize a JSON value to some other form or when the input JSON is different from the POJO class. In this post, we will learn how to use custom deserializer.

Without Custom Deserializer:

Let's first see an example of JSON without using custom deserializer.
 {  
  "id": 10,  
  "name": "John Mathew",  
  "address": {  
   "city": "New York",  
   "country": "US"  
  },  
  "subscribed": true  
 }  
The above JSON represents a user object consisting of id, name, address, and subscribed fields. The address field, in turn, is a nested object consists of city and country fields.

We will unmarshal above JSON to below two entities User and Address:
User.java
 public class User {  
      private Integer id;  
      private String name;  
      private Address address;  
      private boolean subscribed;   
      public User() {  
           super();  
      }  
      public User(Integer id, String name, Boolean subscribed, Address address) {  
           this.id = id;  
           this.name = name;  
           this.address = address;  
           this.subscribed = subscribed;  
      }  
   //getters and setters  
        @Override  
      public String toString() {  
           return "User [id=" + id + ", name=" + name + ", address=" + address + ", subscribed=" + subscribed + "]";  
      }  
 }  

Address.java
 package com.example.demo.entity;  
 public class Address {  
      private String city;  
      private String country;  
      public Address() {  
           super();  
      }  
   public Address(String city, String country) {  
           super();  
           this.city = city;  
           this.country = country;  
      }  
   //getters and setters  
   @Override  
      public String toString() {  
           return "Address [city=" + city + ", country=" + country + "]";  
      }  
 }  

Now let's deserialize it using ObjectMapper as follows:
 ObjectMapper objectMapper = new ObjectMapper();  
 User user = objectMapper.readValue(employeeJson, User.class);  
 System.out.println(user);  

In the above block of code, we have used the readValue method of the object mapper class to read the Java object from JSON string, The readValue method accepts the first argument as JSON string, and the second argument as Java object which needs to be populated.

Let's execute above block of code and we will get the below output on the console:
 User [id=10, name=John Mathew, address=Address [city=New York, country=US], subscribed=true]  
We are able to unmarshal the provided JSON to a User class as our JSON structure matches the POJO class. Now let's see how we can deserialize a JSON, which is different from our User and Address class.

Using Custom Deserializer:

Now let's say we have a below different JSON, which we need to unmarshal it to our User and Address class.
 {  
  "id": 10,  
  "name": "John Mathew",  
  "subscribed": "Y",  
  "city": "New York",  
  "country": "India"  
 }  
The above JSON has a different structure as compared to User class, as "city" and "country" in User class belong to Adress object, which is an object property in User class but the above JSON does not have an address field.

Also, the subscribed field in the above JSON is a string that can have two values "Y"(yes) or "N"(no) whereas subscribed property in User class is of type boolean (true or false).

To unmarshal above JSON, we will need to write a custom deserializer. So let us go ahead and write our custom deserializer called UserDeserializer.
1:  package com.example.demo.util;  
2:  import java.io.IOException;  
3:  import com.example.demo.entity.Address;  
4:  import com.example.demo.entity.User;  
5:  import com.fasterxml.jackson.core.JsonParser;  
6:  import com.fasterxml.jackson.databind.DeserializationContext;  
7:  import com.fasterxml.jackson.databind.JsonNode;  
8:  import com.fasterxml.jackson.databind.deser.std.StdDeserializer;  
9:  public class UserDeserializer extends StdDeserializer<User>{  
10:       public UserDeserializer() {  
11:            this(null);  
12:       }  
13:       public UserDeserializer(Class<?> vc) {  
14:            super(vc);  
15:       }  
16:       @Override  
17:       public User deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {  
18:            JsonNode node = p.getCodec().readTree(p);  
19:            Integer id = (Integer) node.get("id").numberValue();  
20:            String name = node.get("name").textValue();  
21:            String city = node.get("city").textValue();  
22:            String country = node.get("country").textValue();  
23:            String isSubscribed = node.get("subscribed").textValue();  
24:            Boolean subscribed = isSubscribed.equals("Y") ? true : false;  
25:            User user = new User(id, name, subscribed, new Address(city, country));  
26:            return user;  
27:       }  
28:  }  

As you can see, we first get the JsonNode from JsonParser. Using the node we can extract the information using get.

We get the "city" and "country" from the node and use it to construct our Address object.
 new Address(city, country)  

Since subscribed property in User class is of type boolean, we have converted the JSON field "subscribed" to boolean value based on values Y or N. If the value is Y we set the boolean value to true otherwise false. At last, we construct the User class as follows:
 User user = new User(id, name, subscribed, new Address(city, country));  

Finally, we can register our custom deserializer - "UserDeserializer" with the ObjectMapper.
 ObjectMapper objectMapper = new ObjectMapper();  
 SimpleModule simpleModule = new SimpleModule();  
 simpleModule.addDeserializer(User.class, new UserDeserializer());  
 objectMapper.registerModule(simpleModule);  
 User user = objectMapper.readValue(employeeJson, User.class);  

Conclusion:

In this article, we have discussed, how to use an object mapper class to parse the JSON object to the POJO object. Then, we learned how to create and add custom deserializer when the JSON elements data type does not match with our POJO class.

No comments:

Powered by Blogger.