【问题标题】:Jackson serialization exception when trying to serialize LocalDateTime尝试序列化 LocalDateTime 时的杰克逊序列化异常
【发布时间】:2014-02-24 12:58:30
【问题描述】:

我不明白为什么在尝试序列化对象时会出现一个看起来与反序列化相关的异常。我的对象有一个字段是 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

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

更新更多异常:

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

【问题讨论】:

  • 更多代码和更多异常会很好。您如何尝试添加客户(反)序列化程序?异常发生在哪里?
  • 我添加了更多信息,但让我抓狂的是为什么当我试图做相反的事情时它会尝试将字符串转换为对象!

标签: java json serialization jackson


【解决方案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,Jackson 默默地将其反序列化为String

【讨论】:

  • 我认为不可能以任何方式将String 分配给LocalDateTime。 JVM会阻止这种情况。然而,泛型是可能的:如果使用类型参数声明类型,如T,那么在内部它将表示为java.lang.Object(或者如果绑定,则为下限类型),并且该分配将继续并产生异常尝试访问值时。
【解决方案2】:

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

{"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 中,您应该像这样注册自定义(反)序列化器:

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

【讨论】:

    【解决方案3】:

    使用 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
    

    【讨论】:

      猜你喜欢
      • 2012-12-12
      • 2017-06-04
      • 2012-11-07
      • 1970-01-01
      • 1970-01-01
      • 2011-07-03
      • 2020-12-24
      • 2015-04-07
      • 1970-01-01
      相关资源
      最近更新 更多