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

如何使用Jackson的ContextualDeserializer实现泛型List自定义反序列化?

如何用Jackson结合JsonDeserialize和ContextualDeserializer实现泛型Wrapper类的自定义反序列化?

我来帮你搞定这个Jackson泛型反序列化的问题!根据你给出的类结构和JSON格式,咱们可以通过实现ContextualDeserializer和JsonDeserializer来完美适配,下面一步步来:

1. 实现自定义泛型反序列化器

核心是写一个能动态获取泛型参数类型的反序列化器,它既要实现JsonDeserializer<Wrapper<?>>来处理具体的反序列化逻辑,还要实现ContextualDeserializer来获取字段的泛型上下文信息:

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
import com.fasterxml.jackson.databind.deser.BeanProperty;

import java.io.IOException;

public class WrapperDeserializer extends JsonDeserializer<Wrapper<?>> implements ContextualDeserializer {

    // 存储Wrapper<T>中T的具体类型
    private JavaType valueType;

    // 无参构造:Jackson初始化时会先调用这个
    public WrapperDeserializer() {}

    // 带参构造:用于创建携带具体泛型类型的反序列化器实例
    private WrapperDeserializer(JavaType valueType) {
        this.valueType = valueType;
    }

    @Override
    public Wrapper<?> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        Wrapper<?> wrapper = new Wrapper<>();
        // 根据获取到的具体类型,把JSON值反序列化为对应的对象
        Object value = ctxt.readValue(p, valueType);
        wrapper.value = value;
        return wrapper;
    }

    @Override
    public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) throws JsonMappingException {
        // 从当前字段的类型中提取Wrapper<T>的泛型参数T
        JavaType wrapperType = property.getType();
        JavaType actualValueType = wrapperType.containedType(0);
        // 返回一个绑定了具体类型的反序列化器实例
        return new WrapperDeserializer(actualValueType);
    }
}

2. 给Wrapper类绑定反序列化器

在你的Wrapper<T>类上添加@JsonDeserialize注解,指定使用咱们上面写的反序列化器,这样所有Wrapper类型的字段都会自动适配:

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

@JsonDeserialize(using = WrapperDeserializer.class)
public static class Wrapper<T> {
    public T value;
}

3. 测试反序列化逻辑

原JSON是数组结构,我们需要把它包装成{"people": [...]]的格式来匹配People类的people字段,测试代码如下:

import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.List;

public class Main {
    public static void main(String[] args) throws Exception {
        ObjectMapper objectMapper = new ObjectMapper();
        // 适配People类结构的JSON字符串
        String json = "{\"people\": [{\"name\": \"Alice\",\"age\": 37}, {\"name\": \"Bob\",\"age\": 37}]}";
        
        // 反序列化为People对象
        People people = objectMapper.readValue(json, People.class);
        
        // 验证结果
        for (Person person : people.people) {
            System.out.printf("Name: %s, Age: %d%n", person.name.value, person.age.value);
        }
    }

    // 你的原类结构
    public static class People {
        public List<Person> people;
    }

    public static class Person {
        public Wrapper<String> name;
        public Wrapper<Integer> age;
    }

    @JsonDeserialize(using = WrapperDeserializer.class)
    public static class Wrapper<T> {
        public T value;
    }
}

关键逻辑说明

  • ContextualDeserializer的作用:普通的JsonDeserializer无法获取泛型参数的具体类型(比如不知道Wrapper<String>里的String是什么),而ContextualDeserializer可以在反序列化时,根据当前字段的上下文动态提取泛型参数类型,创建对应的反序列化器实例。
  • 动态类型绑定:在createContextual方法中,我们通过property.getType()拿到字段的类型(比如Wrapper<String>),再用containedType(0)提取出泛型参数String,然后返回一个绑定了该类型的WrapperDeserializer实例,这样deserialize方法就能正确把JSON值转成对应的类型并放入Wrapper中。

这样处理后,不管Wrapper的泛型参数是基本类型还是复杂对象,反序列化器都能自动适配,完全满足你的需求!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:49:40