当前位置: 首页 > 知识库问答 >
问题:

从2.10升级时Jackson序列化失败(InvalidDefinitionException:未对java.lang.Object类型执行类型id处理)

郗河
2023-03-14

我正在从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

我从其他类似的帖子(比如这篇和这篇)中了解到,Jackson很难反序列化多态类型,但这是序列化错误,而不是反序列化错误。此外,当我尝试创建自己的异常子类并尝试序列化它时,它工作得很好。我试图将其用作通用序列化程序,所以我不想为每种对象类型手动添加自定义序列化程序——我甚至不知道为什么IllegalFieldValueException似乎是唯一一个无法序列化的类。所以我有两个主要问题:

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

共有1个答案

侯博裕
2023-03-14

简而言之,杰克逊基本上用这个promise打破了这种行为: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

不幸的是,塔图的这一评论显然被忽视了,因为没有办法覆盖或禁用这一检查。即使在最新版本的杰克逊中,它仍然有同样的不良行为。

好消息是,正如您在checkUnsupportedType()方法的实现中所看到的,它只在尝试序列化java下的类时抛出此错误。时间或组织。乔达。时间包裹。这意味着您不必担心在尝试序列化任何其他内容时引发此异常。坏消息是,即使将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!
 类似资料:
  • 我得到了以下几门课: 现在,当我序列化包装在中的时,JSON不包含包含类型ID的属性。虫子?当我序列化到或只序列化到时,它可以正常工作。 编辑:我用一个简单的Spring REST控制器和两个测试制作了一个SSCCE。第一个测试是直接使用,虽然缺少,但它在反序列化中是成功的。第二个测试调用REST控制器并失败,出现错误,因为缺少: 提取类型[class com.example.demo.mySub

  • 问题内容: 我正在尝试制作一个使用Jackson来反序列化POJO的类。 看起来像这样… 我对此实施有2个问题。 首先是我将类类型传递给方法,以便对象映射器知道应反序列化的类型。有使用泛型的更好方法吗? 同样在get方法中,我将一个从objectMapper返回的对象强制转换为T。这看起来特别讨厌,因为我必须在此处强制转换T,然后还必须从调用它的方法中强制转换对象类型。 我在该项目中使用了Robo

  • 我用Jackson编写了自己的序列化程序。它接受一个变量或类,并返回任何简单类型的值。 示例:serialize(new MyClass(2.0))将返回一个值为 2.0 的双精度值,其中 MyClass 如下所示: 因此,为了获得正确的值,我需要设置@JsonValue,但是,当我序列化一个没有@JsonValue注释的对象(例如UUID)时,它会返回预期的UUID字符串。 创建我自己的类没有@

  • 假设我有以下格式的JSON: 我试图避免自定义反序列化程序,并试图将上述JSON(称为Wrapper.java)反序列化为JavaPOJO。“type”字段指示“object”反序列化,即type=foo表示使用foo.java反序列化“object”字段。(如果type=Bar,则使用Bar.java反序列化对象字段)。Metadata/owner将始终以相同的方式对每个元数据使用简单的带Jac

  • 问题内容: 我正在编写一个自定义序列化程序,以将双精度值转换为JSON对象中的字符串。到目前为止,我的代码: 这对于Double(类成员)非常有效,但不适用于double(原始类型)成员。例如, 返回:{“ x”:“ 1111142143543543565865975808”,“ y”:1.1111421435435436E27} 有没有办法让这两种情况都遵循相同的行为? 问题答案: 您可以为原始