java - 从 2.10 升级时 Jackson 序列化失败(InvalidDefinitionException : Type id handling not implemented for type java. lang.Object)

标签 java json serialization jackson jodatime

我正在从 Jackson 2.10 升级到 2.12,突然这个简单的测试(之前运行良好)现在失败了:

ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTyping(DefaultTyping.NON_FINAL);
mapper.valueToTree(new org.joda.time.IllegalFieldValueException("testName", "testValue")); // causes error
java.lang.IllegalArgumentException: Type id handling not implemented for type java.lang.Object (by serializer of type com.fasterxml.jackson.databind.ser.impl.UnsupportedTypeSerializer)
    at com.fasterxml.jackson.databind.ObjectMapper.valueToTree(ObjectMapper.java:3312)
    at com.amazon.ets.util.exception.ExceptionSerializationTest.shouldSerializeException(ExceptionSerializationTest.java:77)
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Type id handling not implemented for type java.lang.Object (by serializer of type com.fasterxml.jackson.databind.ser.impl.UnsupportedTypeSerializer)
    at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77)
    at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1276)
    at com.fasterxml.jackson.databind.DatabindContext.reportBadDefinition(DatabindContext.java:400)
    at com.fasterxml.jackson.databind.JsonSerializer.serializeWithType(JsonSerializer.java:160)
    at com.fasterxml.jackson.databind.ser.impl.TypeWrappedSerializer.serialize(TypeWrappedSerializer.java:32)
    at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480)
    at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319)
    at com.fasterxml.jackson.databind.ObjectMapper.writeValue(ObjectMapper.java:3126)
    at com.fasterxml.jackson.databind.ObjectMapper.valueToTree(ObjectMapper.java:3307)
    ... 24 more

我从其他类似的帖子中收集到了信息,例如 this onethis one Jackson 可以反序列化多态类型,但这是序列化错误,而不是反序列化。此外,当我尝试创建自己的 Exception 子类并尝试序列化它时,它工作得很好。我试图将其用作通用序列化器,因此我不想为每个对象类型手动添加自定义序列化器——我什至不知道为什么 IllegalFieldValueException 特别似乎是唯一失败的类序列化。所以我有两个主要问题:

  1. 当我从 Jackson 2.10 升级到更高版本时,为什么会突然失败?我没有改变任何其他东西!我可以使用配置选项来让它复制早期版本的行为吗?
  2. 为什么 IllegalFieldValueException 是唯一似乎无法序列化的类型?当我尝试序列化其他异常子类或多态类型时,我没有看到此错误。这门课有什么特别之处? (还有其他类可能会导致相同的行为吗?)

最佳答案

简短的回答是, jackson 通过此提交基本上打破了这种行为:https://github.com/FasterXML/jackson-databind/commit/85c9c8544f0c4f01e88241acc1573746df4f755d

讽刺的是,这里的一位开发人员 (tatu) 实际上有一条评论,询问他们是否应该添加一个覆盖选项以允许强制 POJO 序列化:https://github.com/FasterXML/jackson-databind/blob/2.14/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializerFactory.java#L891

不幸的是,tatu 的这条评论显然被忽略了,因为没有办法覆盖或禁用此检查。即使在最新版本的 Jackson 中,它仍然存在同样的不良行为。

好消息是,正如您在 checkUnsupportedType() 的实现中所看到的那样方法,它仅在尝试序列化 java.timeorg.joda.time 包下的类时抛出此错误。这意味着您无需担心在尝试序列化其他任何内容时抛出此异常。坏消息是,即使您添加 JodaModule对于您的 Jackson 映射器,JodaModule 实际上并不包含异常类型,因此您仍然会收到相同的错误。

从长远来看,理想的解决方案是 Jackson 添加一个可配置的序列化选项,以强制 POJO 序列化时间相关类型,和/或更新 JodaModule 以包含异常类型。但现在,您可以通过创建 BeanSerializerFactory 的子类来修复此行为:

public class CustomBeanSerializerFactory extends BeanSerializerFactory {
    public CustomBeanSerializerFactory(SerializerFactoryConfig config) {
        super(config);
    }
    @Override
    protected JsonSerializer<?> _findUnsupportedTypeSerializer(SerializerProvider ctxt, JavaType type, BeanDescription beanDesc) throws JsonMappingException {
        return null;
    }
    @Override
    public SerializerFactory withConfig(SerializerFactoryConfig config) {
        if (_factoryConfig == config) return this;
        return new CustomBeanSerializerFactory(config);
    }
}

然后将您的 ObjectMapper 设置为使用此工厂:

ObjectMapper mapper = new ObjectMapper();
mapper.setSerializerFactory(new CustomBeanSerializerFactory(null));
mapper.enableDefaultTyping(DefaultTyping.NON_FINAL);
mapper.valueToTree(new org.joda.time.IllegalFieldValueException("testName", "testValue")); // no error anymore - yay!

关于java - 从 2.10 升级时 Jackson 序列化失败(InvalidDefinitionException : Type id handling not implemented for type java. lang.Object),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72093555/

相关文章:

java - org.codehaus.jackson.JsonParseException : Unexpected character ('�' (code 65533/0xfffd))

java - 如何将字符串转换为 JsonObject

c# - 通过自定义属性 (json.net) 从序列化中排除属性

为静态方法抛出 java.lang.NoClassDefFoundError 而不是为静态成员抛出

java - "Accounting"JavaFX 中的样式表单元格

java - 解析 JSON 以从数组中获取 'name'

java - 将 Java Spring Rest Controller 中发布的 JSON 映射到 POJO

java - 哪些类型的类不应该被序列化

c# - 用于二进制数据的类似 FileHelpers 的数据导入/导出实用程序?

java - 执行所有测试后清理(spock 框架)