Java 泛型类型的Jackson反序列化程序
我需要为带有泛型的类编写一个自定义反序列化程序。我找不到解决这个问题的方法,但是我无法想象我是唯一一个有这个问题的人。就我所想,有两种方法可以实现这一点,但没有一种是可以实现的:Java 泛型类型的Jackson反序列化程序,java,generics,serialization,jackson,Java,Generics,Serialization,Jackson,我需要为带有泛型的类编写一个自定义反序列化程序。我找不到解决这个问题的方法,但是我无法想象我是唯一一个有这个问题的人。就我所想,有两种方法可以实现这一点,但没有一种是可以实现的: 在反序列化程序的构造函数中向反序列化程序提供类参数不起作用,因为在注册反序列化程序时,Type.Class和具有传递的类实例的反序列化程序实例之间的关系将丢失 例如: public class Foo<T> {} public class FooDeserializer<T> { pub
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));
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
有什么建议吗
编辑:
我找到了解决问题的方法,但这不是一个干净的解决方案:
我用一个Class字段扩展了FooDeserializer,以保存Foo的泛型参数的类型。然后,每次我想将一些json反序列化为一个新的Foo实例时,我都会得到一个新的ObjectMapper实例(我使用ObjectMapper#复制工厂中预配置的实例),并将一个新模块传递给它,该模块包含一个带有类参数的FooDeserializer实例(我现在知道类型)。模块、FoodDeserializer和ObjectMapper副本都是短期存在的,它们仅为这个反序列化操作实例化。正如我所说,不是很干净,但仍然比多次子类化Foo并为每个子类编写反序列化程序要好
例如:
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);
public类FooDeserializer扩展StdDeserializer{
私人阶级类型;
公共反序列化程序(类类型){this.type=type}
...
}
//同时,在反序列化之前:
ObjectMapper mapper=MyObjectMapperFactory.get().copy();
SimpleModule=new SimpleModule(新版本(0,0,1,null,null,null);
module.addDeserializer(Foo.class),新的foodDeserializer(Bar1.class);
mapper.addModule(模块);
foox=mapper.readValue(json,Foo.class);
可能将其放入实用程序方法以隐藏丑陋之处。我认为您不需要编写我们自己的自定义反序列化程序。您可以使用此语法来反序列化从另一个堆栈溢出线程获取的使用泛型的对象
mapper.readValue(jsonString, new TypeReference<Data<String>>() {});
mapper.readValue(jsonString,newTypeReference(){});
两个来源可以帮助您:
您不需要编写自定义反序列化程序。可以通过在作为参数传递给泛型类的类型上放置Jackson注释来反序列化泛型。
注释类
Bar1
,如下所示:
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT)
@JsonTypeName("Bar1")
class Bar1 {
}
现在,当您反序列化Foo
的实例时,Jackson会将类型参数信息放入JSON中。然后,可以将此JSON反序列化为泛型类Foo.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.
ObjectMapper映射器=。。。;
Foo-Foo=新的Foo();
字符串json=objectMapper.writeValueAsString(foo);
foo=mapper.readValue(json,foo.class);//无需指定类型Bar1。
因此,如果可以作为参数传递给Foo的每个类上都有注释,那么JSON就可以反序列化,而不需要在编译时知道类型参数
请参阅和上的Jackson文档。可能会有帮助是的,这在某些情况下可能会起作用。但是,我的类型(示例中为Foo),在其他几个接口中实现Collection。因此jackson使用CollectionDeserializer,而不是简单地映射到Foo类的字段。这不起作用,因为CollectionDeserializer希望json以“[”字符开头,但我的json以{字符,集合的json数组嵌套在根json对象中。
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.