In this post of Spring MVC, we will look creating a custom type converter in Spring MVC. By default, Spring only knows how to convert simple types. This means if we pass simple type in our request, Spring MVC type converter will automatically bind them to correct Java types.
Introduction
In the real world application, we may come across use cases when we need to bind complex object as part of the request data. In this post, we will create a custom type converter in Spring MVC that can convert the request parameter into Java 8 LocalDate and LocalDateTime objects.
1. Creating a Custom Type Converter in Spring MVC
To create a custom type converter, we need to implement the Converter<S,T> interface.While implementing this interface we need to pass following 2 parameters to the method.
- S – The source object type.
- T – The Target object type
In this post, we will create two custom converter for LocaleDate and LocaleDateTime. We will use Spring Boot for this post as it provides an automatic registration of Converter
beans but the core logic will remain same if you are working on a simple Spring MVC application.
2. Maven Setup
We will create a simple Spring Boot based web application. You can create the application either through the IDE or can use Spring Initializr. This is how our pom.xml
look like:
<?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 http://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.0.M4</version>
<relativePath/>
<!-- lookup parent from repository -->
</parent>
<groupId>com.javadevjournal</groupId>
<artifactId>custom-type-converter</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>custom-type-converter</name>
<description>How to create custom type converter in Soring MVC</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</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>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3. Creating Custom LocalDateConverter
To create the custom converter, we will create a custom class LocalDateConverter
and implement the Convert
method in the Converter
interface.
package com.javadevjournal.converter;
import org.springframework.core.convert.converter.Converter;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
@Component
public class LocalDateConverter implements Converter<String, LocalDate> {
/**
* Override the convert method
* @param date
* @return
*/
@Override
public LocalDate convert(String date) {
return LocalDate.parse(date, DateTimeFormatter.BASIC_ISO_DATE);
}
}
[pullquote align=”normal”] You may have to add null check if working with Spring version 4.0 or the older one. We have annotated our class with @Component
annotation.Spring Boot will automatically register this converter. We don’t need any additional configurations to register the custom converter.[/pullquote]
4. Testing Custom Converter
To test our custom converter, let’s create a simple REST controller to get order information based on the date. This is how our REST Controller look like:
package com.javadevjournal.controller;
import com.javadevjournal.data.Order;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDate;
@RestController
@RequestMapping("/orders")
public class OrderController {
private static final Logger LOG = LoggerFactory.getLogger(OrderController.class);
@GetMapping("/order/{date}")
public Order getOrderByDate(@PathVariable("date") LocalDate date) {
LOG.info("Sending order for the request date {} ", date);
return new Order(300.40, "1234", date);
}
}
Let’s build and deploy our application to see things in action:
We are passing date in BASIC_ISO_DATE format since we are using this formatter to parse the request data.If we change the format of the request, we will get an error back from the API.
5. Configuration Spring MVC Application
If you are not using Spring Boot, you may not use the auto-registration feature of the Spring Boot. We need to register the custom type converter in Spring MVC application. This is how we can register our custom converter:
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new LocalDateConverter());
}
}
Summary
In this post, we saw how to create a custom type converter in Spring MVC. We look at creating custom converter in both Spring MVC as well Spring Boot based application. As always, the source code for this post is available on the GitHub.