【问题标题】:Parsing ISO Date String into ZoneDateTime with RestTemplate in Spring在 Spring 中使用 RestTemplate 将 ISO 日期字符串解析为 ZoneDateTime
【发布时间】:2020-01-21 10:13:13
【问题描述】:

我正在通过 RestTemplate 发出 GET 请求,以获取一些包含 dateCreated 字段的数据。日期/时间存储为 ISO 标准字符串,格式如下:

2020-01-14T15:21:52.000+0530

但是,RestTemplate 在此步骤接收到该字符串时无法将此字符串映射到 ZonedDateTime 对象:

ResponseEntity<OrderData[]> responseEntity = restTemplate.getForEntity(urlGETList, OrderData[].class);

然而,当 ISO 字符串被传递给使用 @RequestBody 将 ISO 字符串映射到 ZonedDateTime 使用以下 objectMapper 实现的控制器时,类似的映射工作正常

@Bean
public ObjectMapper objectMapper() {
    JavaTimeModule javaTimeModule = new JavaTimeModule();
    javaTimeModule.addSerializer(ZonedDateTime.class,
            new ZonedDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXX")));
    return Jackson2ObjectMapperBuilder.json().featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) // ISODate
            .modules(javaTimeModule).build();
}

在RestTemplate方法中遇到如下错误

Caused by: java.lang.NoSuchFieldError: ACCEPT_CASE_INSENSITIVE_VALUES
at com.fasterxml.jackson.datatype.jsr310.deser.JSR310DateTimeDeserializerBase.acceptCaseInsensitiveValues(JSR310DateTimeDeserializerBase.java:126)
at com.fasterxml.jackson.datatype.jsr310.deser.JSR310DateTimeDeserializerBase.createContextual(JSR310DateTimeDeserializerBase.java:86)
at com.fasterxml.jackson.datatype.jsr310.deser.InstantDeserializer.createContextual(InstantDeserializer.java:241)
at com.fasterxml.jackson.databind.DeserializationContext.handlePrimaryContextualization(DeserializationContext.java:651)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.resolve(BeanDeserializerBase.java:484)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:293)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:244)
at com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:142)
at com.fasterxml.jackson.databind.DeserializationContext.findContextualValueDeserializer(DeserializationContext.java:444)
at com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.createContextual(ObjectArrayDeserializer.java:128)
at com.fasterxml.jackson.databind.DeserializationContext.handleSecondaryContextualization(DeserializationContext.java:682)
at com.fasterxml.jackson.databind.DeserializationContext.findRootValueDeserializer(DeserializationContext.java:482)
at com.fasterxml.jackson.databind.ObjectMapper._findRootDeserializer(ObjectMapper.java:4190)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4009)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3084)
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:237)
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.read(AbstractJackson2HttpMessageConverter.java:225)
at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:95)
at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:917)
at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:901)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:655)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:613)
at org.springframework.web.client.RestTemplate.getForEntity(RestTemplate.java:312)
at com.increff.assure.service.ClientWrapper.getOrdersByChannel(ClientWrapper.java:111)
at com.increff.assure.dto.OrderDto.getByChannel(OrderDto.java:57)
at com.increff.assure.controller.ChannelOrderController.getByChannel(ChannelOrderController.java:42)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:116)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963)
... 43 more

是什么阻止了 ISO 日期/时间字符串的序列化?

【问题讨论】:

  • 删除模式末尾的 Xes 中的 2 个...并考虑在解析包含偏移量但没有区域。

标签: java spring iso


【解决方案1】:

问题是通过RestTemplate 接收的JSON 无法弄清楚如何将它接收到的ISO DateTime 字符串解析为ZonedDateTime 对象。

我通过在ObjectMapper 中包含一个custom ZonedDateTimeDeserializer 来将ISO 格式字符串解析为ZonedDateTime,从而找到了解决方案。虽然ZonedDateTimeSerializer 是预先提供并完全实现的,但我找不到ZonedDateTimeDeserialzer。所以我的自定义反序列化器会处理这个问题

public class ZonedDateTimeDeserializer extends JsonDeserializer<ZonedDateTime> {
    @Override
    public ZonedDateTime deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)
            throws IOException {
        return ZonedDateTime.parse(
                jsonParser.getText(),
                DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSX")
        );
    }
}

接下来,我将此反序列化器添加到我的ObjectMapper

@Bean
public ObjectMapper objectMapper() {
    JavaTimeModule javaTimeModule = new JavaTimeModule();
    javaTimeModule.addSerializer(ZonedDateTime.class,
            new ZonedDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXX")));
    javaTimeModule.addDeserializer(ZonedDateTime.class,
            new ZonedDateTimeDeserializer());
    ObjectMapper objMapper = Jackson2ObjectMapperBuilder.json().featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) // ISODate
            .modules(javaTimeModule).build();
    return objMapper;
}

当使用RestTemplate时,这处理ZonedDateTime的解析。

【讨论】:

    猜你喜欢
    • 2020-05-23
    • 2021-01-17
    • 2017-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-14
    • 1970-01-01
    相关资源
    最近更新 更多