Разбор строки даты ISO в ZoneDateTime с помощью RestTemplate весной - PullRequest
0 голосов
/ 21 января 2020

Я делаю GET-запрос через RestTemplate, чтобы получить некоторые данные, которые содержат поле 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?

1 Ответ

1 голос
/ 22 января 2020

Проблема заключалась в том, что JSON, полученный через RestTemplate, не мог понять, как проанализировать полученную строку ISO DateTime для объекта ZonedDateTime.

Я нашел решение, включив custom ZonedDateTimeDeserializer в ObjectMapper для анализа строк формата 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;
}

Это обрабатывает синтаксический анализ ZonedDateTime при использовании RestTemplate отлично.

...