当前位置: 首页 > 知识库问答 >
问题:

如何在Jackson中为泛型类型创建自定义反序列化器?

江华容
2023-03-14

想象一下以下场景:

class <T> Foo<T> {
    ....
}

class Bar {
    Foo<Something> foo;
}

我想为Foo编写一个自定义的Jackson反序列化程序。为了做到这一点(例如,为了反序列化具有Foo的类

如何编写这样的反序列化程序?这应该是可能的,因为Jackson是通过键入集合和地图来实现的。

澄清:

似乎有两个部分可以解决这个问题:

1)获取Bar内声明的属性类型foo并使用它来反序列化Foo

2)在反序列化时找出我们正在类Bar内反序列化属性foo以成功完成步骤1)

如何完成1和2?


共有3个答案

路金鑫
2023-03-14

这就是您如何访问/解析自定义Jackson反序列化器的{Target etClass}。当然,您需要为此实现ContextualDeserializer接口。

public class WPCustomEntityDeserializer extends JsonDeserializer<Object> 
              implements ContextualDeserializer {

    private Class<?> targetClass;

    @Override
    public Object deserialize(JsonParser jp, DeserializationContext ctxt)
            throws IOException, JsonProcessingException {

        ObjectCodec oc = jp.getCodec();
        JsonNode node = oc.readTree(jp);

        //Your code here to customize deserialization
        // You can access {target class} as targetClass (defined class field here)
        //This should build some {deserializedClasObject}

        return deserializedClasObject;

    }   

    @Override
    public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property){
        //Find here the targetClass to be deserialized  
        String targetClassName=ctxt.getContextualType().toCanonical();
        try {
            targetClass = Class.forName(targetClassName);
        } catch (ClassNotFoundException e) {            
            e.printStackTrace();
        }
        return this;
    }
}
潘雅珺
2023-03-14

如果目标本身是泛型类型,则属性将为null,因此需要从反序列化上下文中获取valueTtype:

@Override
public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) throws JsonMappingException {
    if (property == null) { //  context is generic
        JMapToListParser parser = new JMapToListParser();
        parser.valueType = ctxt.getContextualType().containedType(0);
        return parser;
    } else {  //  property is generic
        JavaType wrapperType = property.getType();
        JavaType valueType = wrapperType.containedType(0);
        JMapToListParser parser = new JMapToListParser();
        parser.valueType = valueType;
        return parser;
    }
}
常英资
2023-03-14

您可以为泛型类型实现自定义的JsonDeserializer,它还实现了ContextualDeserializer

例如,假设我们有以下包含泛型值的简单包装器类型:

public static class Wrapper<T> {
    public T value;
}

我们现在想要反序列化JSON,如下所示:

{
    "name": "Alice",
    "age": 37
}

一个类的实例,如下所示:

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

实现ContextualDeserializer允许我们基于字段的泛型类型参数为Person类中的每个字段创建特定的反序列化器。这允许我们将名称反序列化为字符串,将年龄反序列化为整数。

完整的反序列化程序如下所示:

public static class WrapperDeserializer extends JsonDeserializer<Wrapper<?>> implements ContextualDeserializer {
    private JavaType valueType;

    @Override
    public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) throws JsonMappingException {
        JavaType wrapperType = property.getType();
        JavaType valueType = wrapperType.containedType(0);
        WrapperDeserializer deserializer = new WrapperDeserializer();
        deserializer.valueType = valueType;
        return deserializer;
    }

    @Override
    public Wrapper<?> deserialize(JsonParser parser, DeserializationContext ctxt) throws IOException {
        Wrapper<?> wrapper = new Wrapper<>();
        wrapper.value = ctxt.readValue(parser, valueType);
        return wrapper;
    }
}

最好先看看这里的createContext,因为Jackson将首先调用它。我们从BeanProperty(例如,包装器)中读取字段的类型

一旦在这个新创建的反序列化器上调用了反序列化,我们可以简单地要求Jackson将值反序列化为内部类型,而不是整个包装类型,并返回一个包含反序列化值的新的包装。

为了注册这个自定义反序列化器,我们需要创建一个包含它的模块,并注册该模块:

SimpleModule module = new SimpleModule()
        .addDeserializer(Wrapper.class, new WrapperDeserializer());

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(module);

如果我们尝试从上面反序列化示例JSON,我们可以看到它按预期工作:

Person person = objectMapper.readValue(json, Person.class);
System.out.println(person.name.value);  // prints Alice
System.out.println(person.age.value);   // prints 37

还有一些关于上下文反序列化器如何在Jackson留档中工作的详细信息。

 类似资料:
  • 我希望在Jackson中为Enum类的集合创建一个自定义反序列化器。因为自定义反序列化器的行为对于所有枚举都是相同的。我想为我的所有枚举类创建公共反序列化程序。 我尝试使一般自定义反序列化如下: 问题是我想在反序列化器中调用枚举静态方法,但无法这样做,因为我没有任何可用的类/枚举上下文信息。 你能帮我知道如何实现它吗?

  • 嗨下面这个问题 如何在Jackson中为泛型类型创建自定义反序列化器? 我想知道如何通过这个来解析 这就是我目前所拥有的 当我试图反序列化一点这个的时候,我得到了一个NPE

  • 问题内容: 我正在尝试制作一个使用Jackson来反序列化POJO的类。 看起来像这样… 我对此实施有2个问题。 首先是我将类类型传递给方法,以便对象映射器知道应反序列化的类型。有使用泛型的更好方法吗? 同样在get方法中,我将一个从objectMapper返回的对象强制转换为T。这看起来特别讨厌,因为我必须在此处强制转换T,然后还必须从调用它的方法中强制转换对象类型。 我在该项目中使用了Robo

  • 问题内容: 我有一个json字符串,应该将其反序列化为以下类 我该怎么做?这是通常的方式 但是我怎么提到T代表什么呢? 问题答案: 你需要为使用的每种通用类型创建一个对象,并将其用于反序列化。例如

  • 我有一个json字符串,我应该将其反序列化为以下类 我怎么做?这是通常的方式 但我怎么说T代表什么呢?