我正在从 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 one和 this one Jackson 可以反序列化多态类型,但这是序列化错误,而不是反序列化。此外,当我尝试创建自己的 Exception 子类并尝试序列化它时,它工作得很好。我试图将其用作通用序列化器,因此我不想为每个对象类型手动添加自定义序列化器——我什至不知道为什么 IllegalFieldValueException 特别似乎是唯一失败的类序列化。所以我有两个主要问题:
- 当我从 Jackson 2.10 升级到更高版本时,为什么会突然失败?我没有改变任何其他东西!我可以使用配置选项来让它复制早期版本的行为吗?
- 为什么 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.time
或 org.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/