You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于属性名使用Jackson反序列化同基类的不同JSON对象?

这个问题确实有点特别——Jackson默认的多态反序列化都是靠值里的类型标识来区分子类,但你这儿是靠顶级键名来判断类型,不过咱们可以通过自定义反序列化器完美解决这个需求,下面一步步来实现:

解决方案:自定义Jackson反序列化器实现基于顶级键的多态反序列化

第一步:定义基类和子类

先把我们的基类和对应子类写好,对应JSON里的foo和bar键:

// 基类
public abstract class BaseClass {
    protected String value;

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
}

// 对应{"foo": "..."}的子类
public class FooClass extends BaseClass {
    // 这里可以添加Foo专属的属性或方法
}

// 对应{"bar": "..."}的子类
public class BarClass extends BaseClass {
    // 这里可以添加Bar专属的属性或方法
}

第二步:编写自定义反序列化器

核心逻辑就在这儿——我们要在反序列化时读取JSON的顶级键,判断是foo还是bar,然后实例化对应的子类:

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;

import java.io.IOException;

public class BaseClassDeserializer extends StdDeserializer<BaseClass> {

    protected BaseClassDeserializer() {
        super(BaseClass.class);
    }

    @Override
    public BaseClass deserialize(JsonParser parser, DeserializationContext context) throws IOException {
        JsonNode rootNode = parser.getCodec().readTree(parser);
        
        // 检查顶级键,匹配对应的子类
        if (rootNode.has("foo")) {
            FooClass foo = new FooClass();
            foo.setValue(rootNode.get("foo").asText());
            return foo;
        } else if (rootNode.has("bar")) {
            BarClass bar = new BarClass();
            bar.setValue(rootNode.get("bar").asText());
            return bar;
        }
        
        // 没有匹配键时的处理,根据业务需求调整
        throw new IOException("无法识别的类型:顶级键不是foo或bar");
    }
}

第三步:注册反序列化器(两种方式选一种)

方式一:用注解绑定到基类

直接在基类上添加注解,让Jackson自动使用我们的反序列化器:

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;

@JsonDeserialize(using = BaseClassDeserializer.class)
public abstract class BaseClass {
    // 基类内容不变
}

方式二:手动注册到ObjectMapper

如果不想修改基类的注解,可以手动配置ObjectMapper:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;

public class TestDeserialization {
    public static void main(String[] args) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        SimpleModule module = new SimpleModule();
        module.addDeserializer(BaseClass.class, new BaseClassDeserializer());
        mapper.registerModule(module);

        // 测试反序列化Foo类型
        String fooJson = "{\"foo\": \"String value\"}";
        BaseClass fooInstance = mapper.readValue(fooJson, BaseClass.class);
        System.out.println(fooInstance.getClass().getSimpleName()); // 输出 FooClass
        System.out.println(fooInstance.getValue()); // 输出 String value

        // 测试反序列化Bar类型
        String barJson = "{\"bar\": \"String value\"}";
        BaseClass barInstance = mapper.readValue(barJson, BaseClass.class);
        System.out.println(barInstance.getClass().getSimpleName()); // 输出 BarClass
        System.out.println(barInstance.getValue()); // 输出 String value
    }
}

扩展小提示

  • 如果后续要加新的子类(比如BazClass对应baz键),只需要在反序列化器的判断逻辑里加新分支就行,扩展性拉满。
  • 如果子类有复杂属性,不用手动赋值,可以用parser.getCodec().treeToValue()直接把节点转成子类对象,比如:
    if (rootNode.has("foo")) {
        return parser.getCodec().treeToValue(rootNode.get("foo"), FooClass.class);
    }
    
    前提是子类字段和JSON结构匹配哦~

内容的提问来源于stack exchange,提问作者user1925405

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:19:14