尝试序列化LocalDateTime时出现Jackson序列化异常

时间:2014-02-24 12:58:31

标签: java json serialization jackson

我无法理解为什么在尝试序列化对象时,我得到一个与反序列化相关的异常。我的对象有一个joda类型为LocalDateTime

的字段
ObjectMapper mapper = new ObjectMapper();
mapper.writeValueAsString(response)); 

我遇到以下异常:

org.codehaus.jackson.map.JsonMappingException: java.lang.String cannot be cast to org.joda.time.LocalDateTime

我正在尝试序列化。为什么它试图将String值转换为对象?我尝试添加自定义反序列化器,但它不起作用。

更新更多例外:

org.codehaus.jackson.map.JsonMappingException: java.lang.String cannot be cast to org.joda.time.LocalDateTime (through reference chain: com.my.AccountDetailResponse["registrationDate"])
at org.codehaus.jackson.map.JsonMappingException.wrapWithPath(JsonMappingException.java:218) ~[jackson-mapper-asl-1.9.13.jar:1.9.13]
at org.codehaus.jackson.map.JsonMappingException.wrapWithPath(JsonMappingException.java:183) ~[jackson-mapper-asl-1.9.13.jar:1.9.13]
at org.codehaus.jackson.map.ser.std.SerializerBase.wrapAndThrow(SerializerBase.java:140) ~[jackson-mapper-asl-1.9.13.jar:1.9.13]
at org.codehaus.jackson.map.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:158) ~[jackson-mapper-asl-1.9.13.jar:1.9.13]
at org.codehaus.jackson.map.ser.BeanSerializer.serialize(BeanSerializer.java:112) ~[jackson-mapper-asl-1.9.13.jar:1.9.13]
at org.codehaus.jackson.map.ser.StdSerializerProvider._serializeValue(StdSerializerProvider.java:610) ~[jackson-mapper-asl-1.9.13.jar:1.9.13]
at org.codehaus.jackson.map.ser.StdSerializerProvider.serializeValue(StdSerializerProvider.java:256) ~[jackson-mapper-asl-1.9.13.jar:1.9.13]
at org.codehaus.jackson.map.ObjectMapper._configAndWriteValue(ObjectMapper.java:2575) ~[jackson-mapper-asl-1.9.13.jar:1.9.13]
at org.codehaus.jackson.map.ObjectMapper.writeValueAsString(ObjectMapper.java:2097) ~[jackson-mapper-asl-1.9.13.jar:1.9.13]

尝试添加反序列化器:

CustomDeserializerFactory deserializerFactory = new CustomDeserializerFactory();
    deserializerFactory.addSpecificMapping(LocalDateTime.class, new   CustomLocalDateTimeDeserializer());
    ObjectMapper mapper = new ObjectMapper();
    mapper.setDeserializerProvider(new StdDeserializerProvider(deserializerFactory));
    try {
        remoteActionDto.setPayload(mapper.writeValueAsString(response));
    } catch (IOException e) {
        logger.error("Can not convert response to json!", e);
       .....
    }

解串器本身。我实际上没有转换,只是概念证明:

private static class CustomLocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {

    @Override
    public LocalDateTime deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        return new LocalDateTime();
    }
}

3 个答案:

答案 0 :(得分:1)

我发现了问题(或者我的同事实际上是这样做的)。这是我见过的最愚蠢的java行为。问题是,包含 LocalDateTime 字段的DTO是通过 reflection 填充的,似乎可以成功设置类型String的值。当您尝试使用此字段时(而不是在设置时),会发生类强制转换异常。

public class MyDto {
  // trough reflection, the contained object is a java.lang.String
  private LocalDateTime myDate; 
}

如果你问为什么会这样 - 因为我们没有为LocalDateTime配置转换器,而是为DateTime配置了转换器。我的同事错误地使用了LocalDateTime,杰克逊默默地将其反序列为String

答案 1 :(得分:0)

我写了一个快速测试课来检查你提供的内容。它似乎运行良好并输出以下内容:

{"value":[2014,2,24,13,42,44,745]}

当然,这可能不是您正在寻找的确切格式,但不管怎样,这是类:

public class JsonSerialization {

    public static void main(final String[] args) {
        try {
            final Response response = new Response();

            final ObjectMapper mapper = new ObjectMapper();
            final String value = mapper.writeValueAsString(response);
            System.out.println(value);
        }
        catch (final Exception e) {
            e.printStackTrace();
        }
    }

    public static class Response {
        LocalDateTime value = new LocalDateTime();
        public LocalDateTime getValue() {
            return this.value;
        }
        public void setValue(final LocalDateTime value) {
            this.value = value;
        }
    }
}        

我想这引出了一些问题:

  • 您的LocalDateTime属性(registrationDate)是否有getter和setter?
  • 您确定错误发生在您认为发生的地方吗?唯一的例外是关于杰克逊的部分,它在哪里说你的代码中调用了writeValueAsString方法?

我知道这不是你问题的一部分,但是在Jackson的1.9.13中,你应该注册这样的自定义(de)序列化器:

SimpleModule module = new SimpleModule("", new Version(1, 0, 0, "");
module.addDeserializer(LocalDateTime.class, new CustomLocalDateTimeDeserializer());
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(module);

答案 2 :(得分:0)

使用JodaModule模块注册您的映射器。

mapper.register(new JodaModule())

或尝试使用JodaMapper:

import com.fasterxml.jackson.datatype.joda.JodaMapper;

public static void main(String args[]){
     DateTime dateTime = new DateTime(12353434);
     JodaMapper mapper = new JodaMapper();
     try {
        serializedString = mapper.writeValueAsString(dateTime);
        System.out.println(serializedString);
    } catch (JsonProcessingException e) {
        e.printStackTrace();
    }
}

控制台输出:

12353434