Generic Top

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE

1. Introduction

In this short tutorial, we'll take a look at how to accept Date, LocalDate and LocalDateTime parameters in Spring REST requests, both at the request and application levels.

2. The Problem

Let's consider a controller with three methods that accept Date, LocalDate and LocalDateTime parameters:

@RestController
public class DateTimeController {

    @PostMapping("/date")
    public void date(@RequestParam("date") Date date) {
        // ...
    }

    @PostMapping("/localdate")
    public void localDate(@RequestParam("localDate") LocalDate localDate) {
        // ...
    }

    @PostMapping("/localdatetime")
    public void dateTime(@RequestParam("localDateTime") LocalDateTime localDateTime) {
        // ...
    }
}

When sending a POST request to any of those methods with a parameter formatted in accordance with ISO 8601 we'll get an exception.

For example, when sending “2018-10-22” to the /date endpoint we will get a bad request error with a message similar to this:

Failed to convert value of type 'java.lang.String' to required type 'java.time.LocalDate'; 
  nested exception is org.springframework.core.convert.ConversionFailedException.

This is because Spring by default cannot convert String parameters to any date or time object.

3. Convert Date Parameters on Request Level

One of the ways to handle this problem is to annotate the parameters with the @DateTimeFormat annotation and provide a formatting pattern parameter:

@RestController
public class DateTimeController {

    @PostMapping("/date")
    public void date(@RequestParam("date") 
      @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) Date date) {
        // ...
    }

    @PostMapping("/local-date")
    public void localDate(@RequestParam("localDate") 
      @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate localDate) {
        // ...
    }

    @PostMapping("/local-date-time")
    public void dateTime(@RequestParam("localDateTime") 
      @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime localDateTime) {
        // ...
    }
}

This way, the Strings will be properly converted to date objects, provided the Strings are formatted using the ISO 8601 format.

We can also use our own conversion patterns. We can just provide a pattern parameter in the @DateTimeFormat annotation:

@PostMapping("/date")
public void date(@RequestParam("date") 
  @DateTimeFormat(pattern = "dd.MM.yyyy") Date date) {
    // ...
}

4. Convert Date Parameters at the Application Level

Another way to handle date and time object conversion in Spring is to provide a global configuration. By following the official documentation we should extend the WebMvcConfigurationSupport configuration and extends its mvcConversionService method:

@Configuration
public class DateTimeConfig extends WebMvcConfigurationSupport {

    @Bean
    @Override
    public FormattingConversionService mvcConversionService() {
        DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService(false);

        DateTimeFormatterRegistrar dateTimeRegistrar = new DateTimeFormatterRegistrar();
        dateTimeRegistrar.setDateFormatter(DateTimeFormatter.ofPattern("dd.MM.yyyy"));
        dateTimeRegistrar.setDateTimeFormatter(DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss"));
        dateTimeRegistrar.registerFormatters(conversionService);

        DateFormatterRegistrar dateRegistrar = new DateFormatterRegistrar();
        dateRegistrar.setFormatter(new DateFormatter("dd.MM.yyyy"));
        dateRegistrar.registerFormatters(conversionService);

        return conversionService;
    }
}

First, we create DefaultFormattingConversionService with a false parameter, which means Spring will not register any formatters by default.

Next, we need to register our custom formats for date and date-time parameters. We need to do it by registering two custom formatting registrars. The first one – DateTimeFormatterRegistar will be responsible for parsing the LocalDate and LocaDateTime objects. The second one – DateFormattingRegistrar will handle the Date object.

5. Summary

In this article, we've learned how to accept the date parameters in Spring MVC requests. We've covered how to do it per request and globally.

We've also learned how to create our own date formatting patterns.

As always all source code is available over on GitHub.

Generic bottom

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE
2 Comments
Oldest
Newest
Inline Feedbacks
View all comments
Alex
Alex
1 year ago

The global register a custom formatter will cause custom converter(implement of Converter interface) invalid. Any idea to resolve that?
Why Spring won’t use the ISO as default? I think the SS style format, the default one, is an American standard, not international.

Loredana Crusoveanu
1 year ago
Reply to  Alex

Hey Alex,

If you use this global configuration, you should register all the converters you want here, including the custom one. You can use the conversionService.addConverter() method.

Cheers.

Comments are closed on this article!