Spring boot custom JSON Serialize – Deserialize Example

Spread the love

1. Overview

This quick article is focused on how to use the @JsonComponent annotation in Spring Boot.

The annotation allows us to expose an annotated class to be a Jackson serializer and/or deserializer without the need to add it to the ObjectMapper manually.

This is part of the core Spring Boot module, so there are no additional dependencies required in a plain Spring Boot application.

Let’s try to understand in which case we should require customized JSON.  In this example, we have used java.time.Instant instance so when spring converts into JSON default format it will look like:

{
    "no": 1,
    "name": "Bob",
    "designation": "Developer",
    "gender": "Male",
    "instant": {
      "epochSecond": 1532150600,
      "nano": 737000000
}

Here is “instant” is not readable as a date. We should send date to a readable format. But  Jackson is not providing support for all the types of objects because generally it will be very based on requirements.

2. Example

In this example, we have used java.time.Instant and converted to yyyy-MM-dd HH:mm:ss a readable format using @JsonComponent

Custom Json in Spring Boot Project Structure

2.1 pom.xml

No other extra dependency is required because Jackson is part of spring boot.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.1.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.dailycodebuffer.example</groupId>
	<artifactId>Spring-boot-custom-JSON</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>Spring-boot-custom-JSON</name>
	<description>Demo project for Spring boot custom JSON</description>

	<properties>
		<java.version>11</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

2.2 DateConverter

@JsonComponent annotation will register as bean or module in spring boot context so it will be used for serializing and deserializing class:

Here we have defined two static class for serializing and deserializing which extends  JsonSerializer and JsonDeserializer respectively.

  • JsonSerializer has an override serialize() method where we can write our custom code for serializing.
  • JsonDeserializer has an override deserialize() method where we can write our custom code for deserializing.
@JsonComponent
public class DateConverter {

    private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";

    private static final SimpleDateFormat sdf1 = new SimpleDateFormat(DATE_FORMAT);


    public static class Serialize extends JsonSerializer<Instant> {

        @Override
        public void serialize(Instant value, JsonGenerator jgen, SerializerProvider provider) {
            try {
                if (value == null) {
                    jgen.writeNull();
                }
                else {
                    jgen.writeString(DateTimeFormatter
                            .ofPattern(DATE_FORMAT).withZone(ZoneId.systemDefault()).format(value) );
                }
            }catch (Exception e){
                e.printStackTrace();
            }

        }
    }

    public static class Deserialize extends JsonDeserializer<Instant> {

        @Override
        public Instant deserialize(com.fasterxml.jackson.core.JsonParser jp, DeserializationContext ctxt) throws IOException {
            try {
                String dateAsString = jp.getText();
                if (dateAsString==null) {
                    return null;
                } else {
                    return Instant.ofEpochMilli(sdf1.parse(dateAsString).getTime());
                }
            }catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    }
}

2.3 EmployeeController

@RestController
public class EmployeeController {

    @RequestMapping("/getEmployees")
    public List<Employee> getEmployees() {
        return Employee.getEmployee();
    }
}

2.4 Employee

public class Employee implements Serializable {

    private int no;
    private String name;
    private String designation;
    private String gender;
    private Instant instant = Instant.now();

    public Employee(int no, String name, String designation, String gender ) {
        this.no = no;
        this.name = name;
        this.designation = designation;
        this.gender = gender;
    }

    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDesignation() {
        return designation;
    }

    public void setDesignation(String designation) {
        this.designation = designation;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public Instant getInstant() {
        return instant;
    }

    public void setInstant(Instant instant) {
        this.instant = instant;
    }

    public static java.util.List<Employee> getEmployee() {
        List<Employee> employees = new ArrayList<>();
        employees.add(new Employee(1, "Bob", "Developer", "Male"));
        employees.add(new Employee(2, "Joy", "Sr. Developer", "Male"));
        employees.add(new Employee(3, "John", "CEO", "Male"));
        employees.add(new Employee(4, "Bat", "Developer", "Male"));
        employees.add(new Employee(5, "Jolly", "Developer", "Female"));
        employees.add(new Employee(6, "Bobby", "Developer", "Female"));
        return employees;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "no=" + no +
                ", name='" + name + '\'' +
                ", designation='" + designation + '\'' +
                ", gender='" + gender + '\'' +
                ", instant=" + instant +
                '}';
    }
}

Output:

Let call http://localhost:8080/getEmployees and check the output:

Custom Json Output for Spring Boot

3. Conclusion

This quick tutorial showed how to quickly add a Jackson serializer/deserializer in a Spring Boot application by leveraging component scanning with the @JsonComponent annotation.

Get the Code

The code snippets can be found over on GitHub.

This Post Has One Comment

Leave a Reply