【问题标题】:com.fasterxml.jackson.databind.JsonMappingException: Can not instantiate value of type [simple type, class java.time.LocalDateTime] from Stringcom.fasterxml.jackson.databind.JsonMappingException:无法从字符串实例化类型 [简单类型,类 java.time.LocalDateTime] 的值
【发布时间】:2016-10-01 14:00:30
【问题描述】:

我的 Jax-RS REST API 中有 Java8 LocalDateTime。我的 webapp 部署在 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 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 调用;

 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'

我该如何克服上述问题?现在我一无所知..我试图把所有东西(尽量避免wildfly的jax-rs复杂支持问题,jackson序列化问题)并解决问题..

有什么帮助吗?

【问题讨论】:

    标签: rest jackson jax-rs wildfly fasterxml


    【解决方案1】:

    您链接到的第一个问题涉及@XxxParam 注释的转换。这就是ParamConverterProvider 的用途。这是与entity body(反)序列化完全不同的(反)序列化过程。

    对于实体(反)序列化,使用MessageBodyReader/MessageBodyWriters。 Jackson 在其JacksonJsonProvider/JacksonJaxbJsonProvider 中提供了一种这样的实现,您当前正在使用它,无论您是否知道。因此,LocalDataTime 的配置需要以某种方式使用该提供程序进行配置。

    LocalDateTime 序列化配置Jackson 支持的唯一方法是通过ObjectMapper。您可以创建自定义Json(De)Serializer,如in this post (Option two) 所述,或者您可以使用this post 中提到的JSR310Module(对于LocalDateTime 已经有自定义Json(De)Serializer)。

    要实际配置JacksonJsonProvider/JacksonJaxbJsonProvider 以使用您配置的ObjectMapper,您可以使用ContextResolver,如前面两个链接中所述,或者您可以使用ObjectMapper 构造JacksonJsonProvider,以及注册该提供者

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

    我个人会选择ContextResolver,如链接中所述。不同之处在于,使用上述代码,ObjectMapper 显式提供给提供者,而使用ContextResolver,在运行时,提供者将在 JAX-RS 注册表中搜索 ContextResolver 类型为 ObjectMapper,然后通过这种方式获得它。

    【讨论】:

    • 抱歉,我对 Hibernate 真的很陌生。感谢您的明确解释。它解决了这个问题。
    【解决方案2】:

    就我而言,添加以下对我有用。

    <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());
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-08-25
      • 2012-06-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-07
      • 2012-06-06
      相关资源
      最近更新 更多