2016-06-02 1 views
0

У меня есть Java8 LocalDateTime в моих API-интерфейсах Jax-RS REST. Мой webapp развернут в wildfly10. Когда я делаю POST-вызов (который включает параметр LocalDateTime как параметр), я получаю следующее исключение;com.fasterxml.jackson.databind.JsonMappingException: не удается создать значение типа [простой тип, класс java.time.LocalDateTime] из String

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.se[email protected]; 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 throws "Unable to find a constructor that takes a String param or a valueOf() or fromString() method for javax.ws.rs.QueryParam" error

и

jaxrs could not find my custom (de)serializers for joda.money type

и

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 call like;

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, проблемы сериализации Jackson) и разобраться в проблеме.

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

ответ

1

Первый вопрос, который вы связали, включает в себя преобразование аннотаций @XxxParam. Это то, что для ParamConverterProvider. Это совершенно другой (де) процесс serailization от объект body (de) сериализация.

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

Единственный способ настройки поддержки Jackson для сериализации LocalDateTime - через ObjectMapper. Вы можете создать таможню Json(De)Serializer, как упомянуто in this post (Option two), или вы можете использовать JSR310Module (у которого уже есть пользовательский Json(De)Serializer для LocalDateTime), упомянутый в this post.

Чтобы реально настроить 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, а затем получить его таким образом.

+0

К сожалению, Im действительно новым для Hibernate. Спасибо за четкое объяснение. Он решил проблему. – Ratha

0

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

<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()); 
Смежные вопросы