ZonedDateTimeDeserializer is missing from jackson jsr310

I parse ZonedDateTime

using like this:

 @JsonSerialize(using = ZonedDateTimeSerializer.class)
 private ZonedDateTime expirationDateTime;

      

I need to be able to deserialize this date correctly. However, there is no deserializer provided by jackson for this:

com.fasterxml.jackson.datatype.jsr310.deser

      

Is there a reason she's missing? What's the most common workaround?

Update : Here's my scenario:

I am creating ZonedDateTime

like this:

ZonedDateTime.of(2017, 1, 1, 1, 1, 1, 1, ZoneOffset.UTC)

      

Then I serialize an object containing a date like this:

public static String toJSON(Object o) {
    ObjectMapper objectMapper = new ObjectMapper();
    StringWriter sWriter = new StringWriter();
    try {
        JsonGenerator jsonGenerator = objectMapper.getJsonFactory().createJsonGenerator(sWriter);
        objectMapper.writeValue(jsonGenerator, o);
        return sWriter.toString();
    } catch (IOException e) {
        throw new IllegalStateException(e);
    }
}

      

And when I try to send it to Spring MVC Controller:

    mockMvc.perform(post("/endpoint/")
            .content(toJSON(myObject))
            .contentType(APPLICATION_JSON))
            .andExpect(status().isOk());

      

The date object that goes into the controller is different.

Before: 2017-01-01T01:01:01.000000001Z

After: 2017-01-01T01:01:01.000000001Z[UTC]

+3


source to share


2 answers


2 values 2017-01-01T01:01:01.000000001Z

and 2017-01-01T01:01:01.000000001Z[UTC]

actually represent the same moment in time, so they are equivalent and can be used without problems (at least, there should be no problem, since they represent the same instant).

The only detail is that Jackson for some reason sets the value ZoneId

to "UTC" when deserializing, which in this case is redundant ( Z

already says the offset is "UTC"). But this shouldn't affect the date value.


A very simple way to get rid of this part [UTC]

is to convert this object to OffsetDateTime

(so it preserves the offset Z

and doesn't use the zone [UTC]

) and then back again ZonedDateTime

:

ZonedDateTime z = // object with 2017-01-01T01:01:01.000000001Z[UTC] value
z = z.toOffsetDateTime().toZonedDateTime();
System.out.println(z); // 2017-01-01T01:01:01.000000001Z

      

After that, the value of the variable Z

will be 2017-01-01T01:01:01.000000001Z

(no part [UTC]

).



But of course this is not ideal as you will have to do it manually for all dates. Your best bet is to write your own deserializer (by extension com.fasterxml.jackson.datatype.jsr310.deser.InstantDeserializer

) that doesn't set the timezone when it's UTC :

public class CustomZonedDateTimeDeserializer extends InstantDeserializer<ZonedDateTime> {
    public CustomZonedDateTimeDeserializer() {
        // most parameters are the same used by InstantDeserializer
        super(ZonedDateTime.class,
              DateTimeFormatter.ISO_ZONED_DATE_TIME,
              ZonedDateTime::from,
              // when zone id is "UTC", use the ZoneOffset.UTC constant instead of the zoneId object
              a -> ZonedDateTime.ofInstant(Instant.ofEpochMilli(a.value), a.zoneId.getId().equals("UTC") ? ZoneOffset.UTC : a.zoneId),
              // when zone id is "UTC", use the ZoneOffset.UTC constant instead of the zoneId object
              a -> ZonedDateTime.ofInstant(Instant.ofEpochSecond(a.integer, a.fraction), a.zoneId.getId().equals("UTC") ? ZoneOffset.UTC : a.zoneId),
              // the same is equals to InstantDeserializer
              ZonedDateTime::withZoneSameInstant, false);
    }
}

      

Then you have to register this deserializer. If you are using ObjectMapper

you need to add it to JavaTimeModule

:

ObjectMapper objectMapper = new ObjectMapper();
JavaTimeModule module = new JavaTimeModule();
// add my custom deserializer (this will affect all ZonedDateTime deserialization)
module.addDeserializer(ZonedDateTime.class, new CustomZonedDateTimeDeserializer());
objectMapper.registerModule(module);

      

If you configure it in Spring, the configuration will be something like this (not tested):

<bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean" id="pnxObjectMapper">
    <property name="deserializersByType">
        <map key-type="java.lang.Class">
            <entry>
                <key>
                    <value>java.time.ZonedDateTime</value>
                </key>
                <bean class="your.app.CustomZonedDateTimeDeserializer">
                </bean>
            </entry>
        </map>
    </property>
</bean>

      

+3


source


I am using this:



        JavaTimeModule javaTimeModule = new JavaTimeModule();
    javaTimeModule.addSerializer(ZonedDateTime.class, new ZonedDateTimeSerializer(DateTimeFormatter.ISO_DATE_TIME));
    javaTimeModule.addDeserializer(ZonedDateTime.class, InstantDeserializer.ZONED_DATE_TIME);

      

0


source







All Articles