com.fasterxml.jackson.databind.JsonMappingException:无法从字符串

时间:2016-06-02 02:12:58

标签: rest jackson jax-rs wildfly fasterxml

我的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);
...

我打电话给像@;

 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复杂支持问题,杰克逊序列化问题)并解决问题..

任何帮助?

2 个答案:

答案 0 :(得分:2)

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

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

配置Jackson支持LocalDateTime序列化的唯一方法是通过它ObjectMapper。您可以按提及的in this post (Option two)创建自定义Json(De)Serializer,也可以使用JSR310Module(已Json(De)Serializer的自定义LocalDateTime){ {3}}

要实际配置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,然后以那种方式获取。

答案 1 :(得分: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());