Spirytus Rektyfikowany
Spirytus Rektyfikowany

Reputation: 199

How to use CustomDateEditor and DateTimeFormat at the same time in spring?

import org.springframework.format.annotation.DateTimeFormat;

@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date etd;

@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date eta;

This code works fine. But I found that an exception is thrown when the time is an empty string, so I add this:

@InitBinder
public void initBinder(ServletRequestDataBinder binder) {
    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
    dateFormat.setLenient(false);
    binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
}

Now empty string convert to null, but only "yyyy-MM-dd" is used, and the hours and minutes are ignored.

For example, eta, before I add InitBinder, the value is '2020-11-11 11:11:11', after adding it is '2020-11-11 00:00:00'.

How to make spring continue to use the format on the DateTimeFormat annotation?

I found this question but he doesn't seem to use DateTimeFormat : How to handle different date formats in Spring MVC controller?

Upvotes: 2

Views: 1359

Answers (3)

Michael Gantman
Michael Gantman

Reputation: 7808

Date class is very much outdated (pun intended). Please switch to package java.time and use one of the implementations of Temporal interface. In your case you should look at LocalDate and LocalDateTime classes. Then your @DateTimeFormat will work correctly

Upvotes: 0

Ken Chan
Ken Chan

Reputation: 90547

Since Spring framework 5.3.5, @DateTimeFormat supports defining a list of fallback patterns for parsing the date time if it fails to parse with the primary pattern. That means you could simply do :

@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date etd;

@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss",fallbackPatterns = "yyyy-MM-dd")
private Date eta;

Upvotes: 3

Babl
Babl

Reputation: 7656

I don't think that you can use both together, as only one of them will be picked by the system, but what you can do is extend standard behavior and add empty string processing. As I like the declarative way of parsing strings based on the @DateTimeFormat annotation I will share the code which shows how easy it is to extend default functionality. So to start with Spring uses AnnotationFormatterFactorys that create formatters to format and parse values of fields annotated with a particular annotation. The @DateTimeFormat annotation has several AnnotationFormatterFactorys but one which parses and formats the java.util.Dates is DateTimeFormatAnnotationFormatterFactory, so what we need to do is just override it add our custom handling and register the formatter. Its is pretty straightforward to do that via WebMvcConfigurationSupport.

@Configuration
public class WebConfig extends WebMvcConfigurationSupport {

    @Override
    protected void addFormatters(FormatterRegistry registry) {
        registry.addFormatterForFieldAnnotation(new DateTimeFormatAnnotationFormatterFactory(){
            @Override
            public Parser<?> getParser(DateTimeFormat annotation, Class<?> fieldType) {
                var defaultParser = super.getParser(annotation, fieldType);
                return (Parser<Object>) (text, locale) -> {
                    // if the text value is empty just return null and do not try to parse
                    if(!StringUtils.hasText(text)){
                        return null;
                    }
                    return defaultParser.parse(text, locale);
                };
            }
        });
    }

}

Upvotes: 0

Related Questions