Search code examples
javaspring-bootdatetimedeserializationjson-deserialization

ZonedDateTime Not Parsed Correctly If Sent As URL Request Parameter


I have a Controller which accepts a POJO (MySearch) representing optional request parameters. Requests succeed when the id and/or name parameter(s) are included.

However, if I include the dateTime parameter like so:

GET /find?dateTime=2019-03-15T22:17:42Z&id=1432&name=Bob

I get an error:

Failed to convert from type [java.lang.String] to type [java.time.ZonedDateTime] 
for value '2019-03-15T22:17:42Z'; nested exception is java.lang.IllegalArgumentException: 
Parse attempt failed for value [2019-03-15T22:17:42Z]

I also tried annotating the dateTime field with @DateTimeFormat(iso = ISO.DATE_TIME), but that didn't help.

Serialization of ZonedDateTime fields in other tests successfully format the date/time similar to yyyy-MM-ddTHH:mm:ssZ in the output.

It is only the deserialization of the ZonedDateTime field in the POJO that I'm having difficulty with.

Controller

@RestController
public class MyController {

    @GetMapping("/find")
    public MyResponse find(MySearch search) {
        // Do stuff ...
    }
}

The POJO

public class MySearch {

    private Integer id;
    
    private String name;
    
    private ZonedDateTime dateTime;
}

Configuration

I configured the ObjectMapper using these two beans:

@Bean
public Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder() {
    return Jackson2ObjectMapperBuilder.json()
            .modulesToInstall(new Jdk8Module(), new JavaTimeModule())
            .featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,
                    DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
}

@Bean
public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
    return builder.build();
}

What am I missing, or doing wrong?

Thanks!


Solution

  • If you want to deserialize this object you need to register it as a new converter. In order to do so you can create a class similar to this one:

    @Configuration
    public class ZoneDateTimeWebMvcConfigurator implements WebMvcConfigurer {
        @Override
        public void addFormatters(FormatterRegistry registry) {
            registry.addConverter(new StringToZoneDateTime());
        }
    
        static class StringToZoneDateTime implements Converter<String, ZonedDateTime> {
            @Override
            public ZonedDateTime convert(String value) {
                return ZonedDateTime.parse(value);
            }
        }
    }