在使用com.fasterxml.jackson(.databind) v3反序列化一个继承自java.util.Properties的类时,出现了一个奇怪的类型转换错误

编程语言 2026-07-10

在尝试将我的应用从Jackson v2升级到Jackson v3时,我遇到了一个问题:

我的应用中有一个类,其中包含对类型为 NodeProperties 的对象的引用,这个类像下面这样派生自 java.util.Properties

public class NodeProperties extends Properties {
    ...
}

在读取包含内部数据结构的JSON序列化版本的JSON文件时,我得到了以下错误:

...
tools.jackson.databind.exc.ValueInstantiationException: Cannot construct instance of `my.application.connections.RESTConnection`, problem: Cannot cast java.util.Properties to my.application.utils.NodeProperties
 at [Source: (BufferedInputStream); line: 38, column: 2]
...

起初我怀疑这个奇怪错误的原因可能是 "NodeProperties" 没有定义额外字段(它只包含我在处理Properties时在应用中使用的几个方便方法)。于是我在 "NodeProperties" 中添加了几个虚拟字段来验证这个假设,但这没有让Jackson满意。它仍然以完全相同的错误失败。因此,这个问题并不是NodeProperties没有字段。

这也不是多态的问题,即Jackson可能不知道某个抽象类的具体子类型,因此实例化一个公有子类或类似的情况。类 "NodeProperties" 并非派生自任何抽象类,也没有实现在这里会使用的任何接口。

但为什么Jackson v3要创建超类 "Properties" 的对象,而不是按应有的那样创建实际的派生类 "NodeProperties" 呢?

注: 我开了这个新线程,因为在我看来这个问题确实与描述在 com.fasterxml.jackson(.databind) v3 has issues deserializing java.util.Properties (this had worked in v2) 的问题不同。在所引用的附录中,我描述了一个问题,结果发现是由于意外地仍在使用Jackson v2而非预期的v3(因为传递性依赖)以及第二个问题是枚举反序列化没有按预期工作。经过修复这两件事(感谢那里有用的回答),我遇到的下一个问题是这个奇怪、错误的对象实例化,显然在新版本的Jackson中处理方式不同。

解决方案

信息太少,难以判断。

我知道你提到这不是多态问题,但我觉得它几乎就是(Properties继承自Hashtable,而Jackson的反序列化实现也是如此)。

据我所知,Jackson 3在反序列化方面更加严格、也更明确,不再在父类和子类之间进行自动转换(Properties - NodeProperties)。

我有一个朋友也遇到了类似的问题。试试这个:

@JsonDeserialize(as = NodeProperties.class)
public class NodeProperties extends Properties {
    public NodeProperties() { // Not pretty sure it is needed
        super();
    }

    // Your fantastic methods :)
}

如果不行,你也可以自己实现一个反序列化器,继承JsonDeserializer或 ValueDeserializer:

public class NodePropertiesDeserializer extends ValueDeserializer<NodeProperties> {

    @Override
    public NodeProperties deserialize(JsonParser p, DeserializationContext ctxt) 
            throws IOException {
        Properties props = p.readValueAs(Properties.class);
        NodeProperties nodeProps = new NodeProperties();
        nodeProps.putAll(props);
        return nodeProps;
    }
}

并把这个加入到你的NodeProperties类中:@JsonDeserialize(using = NodePropertiesDeserializer.class)。如果你不喜欢注解,你也可以手动将其添加为反序列化器。

另外一个选项,我没有实际测试过,但既然你在对你自己的数据结构进行序列化,我认为你可以使用 @JsonTypeInfo 注解,可能更简洁、只需一行,但会让JSON与框架的耦合更紧密,显得不太干净。

import tools.jackson.databind.annotation.JsonTypeInfo;

@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class")
public class NodeProperties extends Properties {
    // Completely useful stuff here
}

这应该在该类的JSON序列化过程中包含一个属性,指示在反序列化时Jackson应该映射到哪个类。类似于

{
  "@class": "my.application.utils.NodeProperties",
  "timeout": 5000,
  "host": "localhost"
}
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章