如何使用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
相关产品推荐
相关产品推荐

