Spring deserializes a LocalDate in a @RequestBody differently from one in a @RequestParam - why, and can they be the same?

前端 未结 2 1086
遥遥无期
遥遥无期 2021-02-15 17:27

QUESTION: Spring appears to use different deserialization methods for LocalDate depending on whether it appears in a @RequestBody or a request @R

2条回答
  •  遇见更好的自我
    2021-02-15 17:59

    Per @Andreas in comments, the Spring Framework uses Jackson to deserialize @RequestBody but Spring itself deserializes @RequestParam. This is the source of the difference between the two.

    This answer shows how to use @ControllerAdvice and @InitBinder to customize the deserialization of @RequestParam. The code I ultimately used follows:

    import org.springframework.web.bind.WebDataBinder;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.InitBinder;
    
    import java.beans.PropertyEditorSupport;
    import java.text.Format;
    import java.time.*;
    import java.time.format.DateTimeFormatter;
    import java.util.function.Function;
    
    @ControllerAdvice
    public class ControllerAdviceInitBinder {
    
        private static class Editor extends PropertyEditorSupport {
    
            private final Function parser;
            private final Format format;
    
            public Editor(Function parser, Format format) {
    
                this.parser = parser;
                this.format = format;
            }
    
            public void setAsText(String text) {
    
                setValue(this.parser.apply(text));
            }
    
            public String getAsText() {
    
                return format.format((T) getValue());
            }
        }
    
        @InitBinder
        public void initBinder(WebDataBinder webDataBinder) {
    
            webDataBinder.registerCustomEditor(
                    Instant.class,
                    new Editor<>(
                            Instant::parse,
                            DateTimeFormatter.ISO_INSTANT.toFormat()));
    
            webDataBinder.registerCustomEditor(
                    LocalDate.class,
                    new Editor<>(
                            text -> LocalDate.parse(text, DateTimeFormatter.ISO_LOCAL_DATE),
                            DateTimeFormatter.ISO_LOCAL_DATE.toFormat()));
    
            webDataBinder.registerCustomEditor(
                    LocalDateTime.class,
                    new Editor<>(
                            text -> LocalDateTime.parse(text, DateTimeFormatter.ISO_LOCAL_DATE_TIME),
                            DateTimeFormatter.ISO_LOCAL_DATE_TIME.toFormat()));
    
            webDataBinder.registerCustomEditor(
                    LocalTime.class,
                    new Editor<>(
                            text -> LocalTime.parse(text, DateTimeFormatter.ISO_LOCAL_TIME),
                            DateTimeFormatter.ISO_LOCAL_TIME.toFormat()));
    
            webDataBinder.registerCustomEditor(
                    OffsetDateTime.class,
                    new Editor<>(
                            text -> OffsetDateTime.parse(text, DateTimeFormatter.ISO_OFFSET_DATE_TIME),
                            DateTimeFormatter.ISO_OFFSET_DATE_TIME.toFormat()));
    
            webDataBinder.registerCustomEditor(
                    OffsetTime.class,
                    new Editor<>(
                            text -> OffsetTime.parse(text, DateTimeFormatter.ISO_OFFSET_TIME),
                            DateTimeFormatter.ISO_OFFSET_TIME.toFormat()));
    
            webDataBinder.registerCustomEditor(
                    ZonedDateTime.class,
                    new Editor<>(
                            text -> ZonedDateTime.parse(text, DateTimeFormatter.ISO_ZONED_DATE_TIME),
                            DateTimeFormatter.ISO_ZONED_DATE_TIME.toFormat()));
        }
    }
    

提交回复
热议问题