com.fasterxml.jackson.databind.JsonMappingException: невозможно создать экземпляр значения типа [простой тип, класс java.time.LocalDateTime] из строки

У меня есть Java8 LocalDateTime в моих REST API Jax-RS. Мое веб-приложение развернуто в wildfly10. Когда я делаю вызов POST (который включает LocalDateTime в качестве параметра), я получаю следующее исключение;

Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not instantiate value of type [simple type, class java.time.LocalDateTime] from String value ('2016-06-02T00:08:25.605Z'); no single-String constructor/factory method
 at [Source: io.undertow.servlet.spec.ServletInputStreamImpl@396d1714; line: 2, column: 3] (through reference chain: com.leightonobrien.core.model.base.Company["created"])
    at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148)
    at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:843)
    at com.fasterxml.jackson.databind.deser.ValueInstantiator._createFromStringFallbacks(ValueInstantiator.java:277)
    at com.fasterxml.jackson.databind.deser.std.StdValueInstantiator.createFromString(StdValueInstantiator.java:284)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromString(BeanDeserializerBase.java:1150)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:153)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:144)
    at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:523)
    at com.fasterxml.jackson.databind.deser.impl.FieldProperty.deserializeAndSet(FieldProperty.java:101)
    at com.fasterxml.jackson.databind.deser.impl.BeanPropertyMap.findDeserializeAndSet(BeanPropertyMap.java:285)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:248)

На основе следующих руководств;

Wildfly выдает Unable to find the конструктор, который принимает параметр String или метод valueOf() или fromString() для ошибки javax.ws.rs.QueryParam

а также

jaxrs может не могу найти мои пользовательские (де)сериализаторы для типа joda.money

а также

https://github.com/FasterXML/jackson-datatype-jsr310

Я написал своего провайдера и прописал в пути приложения;

package com.test;

import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

import javax.ws.rs.ext.ParamConverter;
import javax.ws.rs.ext.ParamConverterProvider;
import javax.ws.rs.ext.Provider;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;

@Provider
public class LocalDateTimeConverterProvider extends JacksonJsonProvider implements ParamConverterProvider {

    private final LocalDateTimeConverter converter = new LocalDateTimeConverter();

    @Override
    public <T> ParamConverter<T> getConverter(Class<T> rawType, Type genericType, Annotation[] annotations) {
        if (!rawType.equals(LocalDateTime.class))
            return null;
        return (ParamConverter<T>) converter;
    }

    public class LocalDateTimeConverter implements ParamConverter<LocalDateTime> {

        @Override
        public LocalDateTime fromString(String value) {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
            LocalDateTime dateTime = LocalDateTime.parse(value, formatter);
            return dateTime;
        }

        @Override
        public String toString(LocalDateTime value) {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
            String formattedDateTime = value.format(formatter);
            return formattedDateTime;
        }

    }

    public LocalDateTimeConverterProvider() {

        ObjectMapper mapper = new ObjectMapper();

        mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

        mapper.registerModule(new JavaTimeModule());

        setMapper(mapper);
    }

}



import javax.ws.rs.ApplicationPath;

@ApplicationPath("/rest")
public class RestApplication extends Application {
@Override
    public Set<Class<?>> getClasses() {
        HashSet<Class<?>> set = new HashSet<Class<?>>();
        set.add(com.test.JsonMoneyProvider.class);
        set.add(com.test.DurtaionConverterProvider.class);
        set.add(com.test.LocalDateTimeConverterProvider.class);
        set.add(com.test.MoneyConverterProvider.class);
...

Я делаю вызов POST как;

 curl -X POST --header 'Content-Type: application/json' -d '{
  "created": "2016-06-02T00:08:25.605Z",
  "updated": "2016-06-02T00:08:25.605Z",
  "id": 0,
  "code": "string",
  "name": "string",
  "abn": "string",
  "addresses": [
    {
      "id": 0,
      "address1": "string",
      "address2": "string",
      "city": "string",
      "state": "string",
      "postcode": "string",
      "country": "string",
      "gps": {
        "latitude": {
          "latitude": 0,
          "value": 0
        },
        "longitude": {
          "longitude": 0,
          "value": 0
}' 'http://localhost:8080/test2dbwar/rest/Companys'

Как я могу преодолеть вышеуказанную проблему? Теперь я не в курсе. Я попытался собрать все вещи (постарайтесь избежать сложной проблемы поддержки jax-rs wildfly, проблемы с сериализацией Джексона) и разобраться с проблемой.

Любая помощь?


person Ratha    schedule 02.06.2016    source источник


Ответы (2)


Первый вопрос, на который вы ссылаетесь, включает преобразование аннотаций @XxxParam. Для этого и нужен ParamConverterProvider. Это совершенно другой процесс (де)сериализации, чем процесс (де)сериализации entity body.

Для (де)сериализации объектов используются MessageBodyReader/MessageBodyWriters. Джексон предоставляет одну такую ​​реализацию в JacksonJsonProvider/JacksonJaxbJsonProvider, которую вы сейчас используете, знаете ли вы об этом или нет. Таким образом, конфигурация LocalDataTime должна быть каким-то образом настроена с этим провайдером.

Единственный способ настроить поддержку Jackson для сериализации LocalDateTime — это ObjectMapper. Вы можете создать собственный Json(De)Serializer, как указано в этом сообщении (второй вариант), или вы можете использовать JSR310Module (который уже имеет пользовательский Json(De)Serializer для LocalDateTime), упомянутый в этом сообщении.

Чтобы фактически настроить JacksonJsonProvider/JacksonJaxbJsonProvider для использования настроенного ObjectMapper, вы можете использовать ContextResolver, как указано в обеих предыдущих ссылках, или вы можете создать JacksonJsonProvider с ObjectMapper и зарегистрировать этого провайдера.

ObjectMapper mapper = new ObjectMapper();
mapper..configurModuleOrSerializer
JacksonJsonProvider provider = new JacksonJsonProvider(mapper);
registerProvier(provider)

Лично я бы выбрал ContextResolver, как указано в ссылках. Разница в том, что в приведенном выше коде ObjectMapper предоставляется провайдеру явно, тогда как с ContextResolver во время выполнения провайдер будет искать в реестре JAX-RS ContextResolver типа ObjectMapper, а затем получать его таким образом.

person Paul Samsotha    schedule 02.06.2016
comment
Извините, я действительно новичок в Hibernate. Спасибо за ясное объяснение. Это решило проблему. - person Ratha; 02.06.2016

В моем случае добавление следующего работает для меня.

<dependency>
  <groupId>com.fasterxml.jackson.datatype</groupId>
  <artifactId>jackson-datatype-jsr310</artifactId>
  <version>2.8.9</version
</dependency>

и настройте ObjectMapper следующим образом:

ObjectMapper mapper = new ObjectMapper().registerModule(new JavaTimeModule());
person ysl    schedule 10.08.2017