Tuesday, 7 January 2020

Jackson: Custom Serializer


Suppose you have an Employee and Address class defined like below.
public class Employee {
        private String firstName;
        private String lastName;
        private Address address;
        ....
        ....
}

public class Address {

        private String street;
        private String city;
        private String country;
        ....
        ....
}


When you serialize an Employee object to json string, it looks like below.
{
        "firstName": "Rama Krishna",
        "lastName": "Gurram",
        "address": {
                "street": "Chowdeswari Street",
                "city": "Bangalore",
                "country": "India"
        }
}


Sometimes, you may want to customize serialization structure. For example, I want address as comma separated values like below.
{
        "firstName": "Rama Krishna",
        "lastName": "Gurram",
        "address": {
                "address": "Chowdeswari Street,Bangalore,India"
        }
}

We can achieve this customization using a custom serializer.

How to define custom serializer?

Step 1: Write a serialzier by extending JsonSerializer class.
public class AddressSerializer extends JsonSerializer<Address> {

        @Override
        public void serialize(Address address, JsonGenerator gen, SerializerProvider serializers)
                        throws IOException, JsonProcessingException {
                gen.writeStartObject();
                gen.writeStringField("address", getCommmaSeparatedAddress(address));
                gen.writeEndObject();

        }

        private static String getCommmaSeparatedAddress(Address address) {
                StringBuilder builder = new StringBuilder();
                builder.append(address.getStreet()).append(",").append(address.getCity()).append(",")
                                .append(address.getCountry());
                return builder.toString();
        }

}


Step 2: Define module by extending SimpleModule and map custom serializer to Address type.
public class AddressModule extends SimpleModule {

        private static final long serialVersionUID = 1L;
        
        private static final String NAME = "CustomAddressModule";
        private static final VersionUtil VERSION_UTIL = new VersionUtil() {
        };

        public AddressModule() {
                super(NAME, VERSION_UTIL.version());
                addSerializer(Address.class, new AddressSerializer());
        }
}

Step 3: Register AddressModule to ObjectMapper.
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new AddressModule());

Find the below working application.


Address.java
package com.sample.app.model;

public class Address {

        private String street;
        private String city;
        private String country;

        public String getStreet() {
                return street;
        }

        public void setStreet(String street) {
                this.street = street;
        }

        public String getCity() {
                return city;
        }

        public void setCity(String city) {
                this.city = city;
        }

        public String getCountry() {
                return country;
        }

        public void setCountry(String country) {
                this.country = country;
        }

}


Employee.java
package com.sample.app.model;

public class Employee {
        private String firstName;
        private String lastName;
        private Address address;

        public String getFirstName() {
                return firstName;
        }

        public void setFirstName(String firstName) {
                this.firstName = firstName;
        }

        public String getLastName() {
                return lastName;
        }

        public void setLastName(String lastName) {
                this.lastName = lastName;
        }

        public Address getAddress() {
                return address;
        }

        public void setAddress(Address address) {
                this.address = address;
        }

        @Override
        public String toString() {
                StringBuilder builder = new StringBuilder();
                builder.append("Employee [firstName=");
                builder.append(firstName);
                builder.append(", lastName=");
                builder.append(lastName);
                builder.append("]");
                return builder.toString();
        }

}


AddressSerializer.java
package com.sample.app.serializer;

import java.io.IOException;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.sample.app.model.Address;

public class AddressSerializer extends JsonSerializer<Address> {

        @Override
        public void serialize(Address address, JsonGenerator gen, SerializerProvider serializers)
                        throws IOException, JsonProcessingException {
                gen.writeStartObject();
                gen.writeStringField("address", getCommmaSeparatedAddress(address));
                gen.writeEndObject();

        }

        private static String getCommmaSeparatedAddress(Address address) {
                StringBuilder builder = new StringBuilder();
                builder.append(address.getStreet()).append(",").append(address.getCity()).append(",")
                                .append(address.getCountry());
                return builder.toString();
        }

}


AddressModule.java
package com.sample.app.module;

import com.fasterxml.jackson.core.util.VersionUtil;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.sample.app.model.Address;
import com.sample.app.serializer.AddressSerializer;

public class AddressModule extends SimpleModule {

        private static final long serialVersionUID = 1L;
        
        private static final String NAME = "CustomAddressModule";
        private static final VersionUtil VERSION_UTIL = new VersionUtil() {
        };

        public AddressModule() {
                super(NAME, VERSION_UTIL.version());
                addSerializer(Address.class, new AddressSerializer());
        }
}


App.java
package com.sample.app;

import java.io.IOException;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sample.app.model.Address;
import com.sample.app.model.Employee;
import com.sample.app.module.AddressModule;

public class App {

        public static void main(String args[]) throws JsonParseException, JsonMappingException, IOException {
                
                ObjectMapper mapper = new ObjectMapper();
                mapper.registerModule(new AddressModule());
                
                Address address = new Address();
                address.setCity("Bangalore");
                address.setStreet("Chowdeswari Street");
                address.setCountry("India");
                
                Employee emp = new Employee();
                emp.setFirstName("Rama Krishna");
                emp.setLastName("Gurram");
                emp.setAddress(address);
                
                String json = mapper.writeValueAsString(emp);
                System.out.println(json);

        }

}


Run App.java, you will see below message in console.
{"firstName":"Rama Krishna","lastName":"Gurram","address":{"address":"Chowdeswari Street,Bangalore,India"}}


In my next post, I will explain how to specify the serializer using @JsonSerialize annotation


Previous                                                    Next                                                  &nbs

No comments:

Post a Comment