杰克逊解串器的泛型类型 [英] Jackson deserializer for generic type

查看:161
本文介绍了杰克逊解串器的泛型类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要为泛型类编写一个自定义的反序列化器。我找不到办法做到这一点,但我无法想象我是唯一有这个问题的人。据我的想法,有两种方法可以实现,但没有一种可以实现:

I need to write a custom deserializer for a class with generics. I couldn't find a way to do this, however I cannot imagine I'm the only one with this problem. As far as I've thought through it, there would be two ways to implement this, yet none of them are implementable:


  1. 提供一个反序列化器的构造函数中的反序列化器的类参数不起作用,因为在注册反序列化器时,Type.class与具有传递的Class实例的反序列化器实例之间的关系丢失。

例如:

For example:

public class Foo<T> {}
public class FooDeserializer<T> {
    public FooDeserializer(Class<T> type) { ... }
    ...
}
// Boilerplate code...
module.addDeserializer(Foo.class, new FooDeserializer<Bar1>(Bar1.class));
module.addDeserializer(Foo.class, new FooDeserializer<Bar2>(Bar2.class));

这不起作用,当ObjectMapper实例获取Foo的实例时,没有类型信息通用参数可用(类型擦除),因此它只是选择注册的最后一个反序列化程序。

This doesn't work, when an ObjectMapper instance gets an instance of Foo, there's no type information of the generic parameter available (type erasure) so it simply chooses the last deserializer registered.



$ b $保留泛型类型在类中的引用,因为类的实例化版本不能传递给反序列化器(接口是readValue(String,Class))。 b

例如:

For example:

String json = "...";
ObjectMapper mapper = ...;
Foo<Bar1> foo = new Foo<>(Bar1.class);
foo = mapper.readValue(json, Foo.class); // Can't pass empty foo instance with Class<?> field containing Bar1.class

需要类似这样的内容:

mapper.readValue(json, Foo.class, Bar1.class); // Doesn't exist in jackson

任何建议如何做到这一点?

Any suggestions how to do this?

编辑:
我找到了一种解决问题的方法,但它不是一个干净的解决方案:

I found a way to solve the problem, however it's not a clean solution:

我扩展了FooDeserializer用一个Class字段来保存Foo的泛型参数的类型。然后,每当我想将一些json反序列化为一个新的Foo实例时,我都会得到一个新的ObjectMapper实例(我在工厂预配置的实例中使用ObjectMapper#copy),并将一个包含FooDeserializer实例的新模块传递给它类参数(我知道此时的类型)。模块,FooDeserializer和ObjectMapper副本是短暂的生活,他们只为这个单一的反序列化操作实例化。正如我所说,不是很干净,但仍然比分类Foo许多次,并写每个反序列化器。

I extend the FooDeserializer with a Class field to save the type of Foo's generic parameter. Then, every time I want to deserialize some json into a new Foo instance, I get a new ObjectMapper instance (I use ObjectMapper#copy on a preconfigured instance from a factory) and pass it a new Module which contains an instance of the FooDeserializer with the class parameter (I know the type at this time). Module, FooDeserializer and the ObjectMapper copy are short living, they only get instantiated for this single deserialization action. As I said, not very clean, but still better than subclassing Foo many times and writing a deserializer for each.

示例:

public class FooDeserializer<T> extends StdDeserializer<T> {
    private Class<T> type;
    public FooDeserializer(Class<T> type) { this.type = type }
    ...
}

// Meanwhile, before deserialization:
ObjectMapper mapper = MyObjectMapperFactory.get().copy();
SimpleModule module = new SimpleModule(new Version(0,0,1,null,null,null);
module.addDeserializer(Foo.class, new FooDeserializer(Bar1.class);
mapper.addModule(module);
Foo<Bar1> x = mapper.readValue(json, Foo.class); 

可能把这个变成了一种实用的方法来掩盖丑陋。

Probably putting this into a utility method to hide the uglyness.

推荐答案

你不需要编写一个自定义的反序列化器,通过将Jackson注释放在作为参数传递给泛型类的类型上,可以反序列化泛型。

Annotate class Bar1 如下所示:

You don't need to write a custom deserializer. A generic can be deserialized by putting Jackson annotations on the type that is passed as parameter to the generic class.
Annotate class Bar1 as follows:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT)
@JsonTypeName("Bar1")
class Bar1 {

}

现在,当您反序列化 Foo< Bar1> 的实例时,Jackson会将类型参数信息放入JSON中,然后将这个JSON反序列化为泛型类 Foo.class 就像反序列化其他类一样。

Now when you deserialize an instance of Foo<Bar1>, Jackson will put type parameter info into JSON. This JSON can then be deserialized into generic class Foo.class just as you would deserialize any other class.

ObjectMapper mapper = ...;
Foo<Bar1> foo = new Foo<Bar1>();
String json = objectMapper.writeValueAsString(foo);
foo = mapper.readValue(json, Foo.class); // no need to specify the type Bar1.

因此,如果每个可以作为参数传递给Foo的类都有注释,那么JSON可以在编译时无需知道类型参数就可以反序列化。

So if every class that can be passed as parameter to Foo has annotations on it, then JSON can be deserialized without knowing the type parameter at compile time.

请参阅多态反序列化注解

这篇关于杰克逊解串器的泛型类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆