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

如何让Jackson将JSON反序列化为含工厂实例化的泛型包装对象?

问题描述

给定如下JSON:

{
"data": 
    {
     "id": 1,
     "name": "Sergey"
    }
}

需要将其反序列化为Data<Person>实例,相关类定义如下:

  • Person类(带标准构造方法):
public class Person {
    private int id;
    private String name;
    public Person(int id, String name) {
        this.id = id;
        this.name = name;
    }
}
  • Data泛型类(仅通过静态工厂方法build实例化,私有构造方法):
public final class Data<T> {

    private final T data;

    private Data(T data) {
        this.data = data;
    }

    public static <T> Data<T> build(T data) {
        return new Data<>(data);
    }
}

需解决两个问题:

  1. 如何用Jackson以最简洁高效的方式实现该反序列化?
  2. Baeldung相关文章是否有对应示例方案?是否存在更简洁清晰的实现方式?

解决方案

方案一:使用Jackson注解(最简洁,官方推荐)

直接在Data类的静态工厂方法上添加Jackson注解,让框架自动识别并使用该方法完成实例化:

public final class Data<T> {

    private final T data;

    private Data(T data) {
        this.data = data;
    }

    @JsonCreator
    public static <T> Data<T> build(@JsonProperty("data") T data) {
        return new Data<>(data);
    }

    // 若需支持序列化,添加对应Getter并标记@JsonProperty
    @JsonProperty("data")
    public T getData() {
        return data;
    }
}

完成注解修改后,直接使用ObjectMapper即可完成反序列化:

ObjectMapper mapper = new ObjectMapper();
// Java 8+ 需添加jackson-module-parameter-names依赖,注册模块后可自动识别Person构造参数
mapper.registerModule(new ParameterNamesModule());
// 使用TypeReference指定泛型类型
Data<Person> person = mapper.readValue(jsonString, new TypeReference<Data<Person>>() {});

注:如果无法引入参数名称模块,也可以直接在Person的构造方法参数上添加@JsonProperty,明确参数与JSON字段的映射关系。

方案二:自定义反序列化器(无需修改Data类源码)

如果无法修改Data类的代码,可编写自定义反序列化器实现:

public class DataDeserializer<T> extends StdDeserializer<Data<T>> {
    private final JavaType valueType;

    public DataDeserializer(JavaType valueType) {
        super(Data.class);
        this.valueType = valueType;
    }

    @Override
    public Data<T> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        JsonNode rootNode = p.getCodec().readTree(p);
        JsonNode dataNode = rootNode.get("data");
        // 将data节点反序列化为指定泛型类型
        T data = ctxt.readValue(dataNode.traverse(p.getCodec()), valueType);
        return Data.build(data);
    }
}

使用时需构造对应的泛型类型并注册反序列化器:

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new ParameterNamesModule());

// 构造Data<Person>的JavaType
JavaType dataPersonType = TypeFactory.defaultInstance()
        .constructParametricType(Data.class, Person.class);
// 注册自定义反序列化器
mapper.registerModule(new SimpleModule()
        .addDeserializer(Data.class, new DataDeserializer<>(dataPersonType)));

Data<Person> person = mapper.readValue(jsonString, dataPersonType);

关于Baeldung文章的说明

部分Baeldung文章存在AI生成内容的情况,但针对泛型类通过静态工厂方法反序列化的场景,其给出的常规示例方案与上述方案一完全一致——即通过@JsonCreator和@JsonProperty标记静态工厂方法。这也是Jackson官方推荐的最简洁原生实现方式,不存在更简化的原生实现手段。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 05:07:40