在使用enableDefaultTyping和提供通用TypeRefernce时遇到了反序列化问题。杰克逊似乎无法确定哪种类型的信息更重要。这个测试案例证明了这个问题:
@Test
public void roundTripTest() throws JsonGenerationException,
JsonMappingException, IOException {
// 0 Value Test
Integer[] integers = new Integer[] {};
Wrap<Integer[]> beforeResult = new Wrap<Integer[]>(integers);
File file = new File("/tmp/jsonTest");
mapper.writeValue(file, beforeResult);
TypeReference<Wrap<Integer[]>> typeRef = new TypeReference<JacksonMapperTest.Wrap<Integer[]>>() {
};
Wrap<Integer[]> afterResult = mapper.readValue(file, typeRef);
assertNotNull(afterResult);
}
public static class Wrap<T> {
private T wrapped;
public Wrap() {
}
public Wrap(T wrapped) {
this.wrapped = wrapped;
}
public T getWrapped() {
return wrapped;
}
public void setWrapped(T wrapped) {
this.wrapped = wrapped;
}
}
mapper是:
mapper = new ObjectMapper();
mapper.enableDefaultTyping();
,例外是:
org.codehaus.jackson.map.JsonMappingException: No suitable constructor found for type [simple type, class JacksonMapperTest$Wrap<[Ljava.lang.Integer;>]: can not instantiate from JSON object (need to add/enable type information?)
很奇怪,是吗?通过使用beforeResult.getClass而不是TypeRefernce,可以省略问题,但它仍然不是首选行为。
为了解决这个问题,我有没有错过任何选择?
我使用的是Jackson 1.9.3
[编辑] 使用地图而不是数据作为包装对象按预期工作!
答案 0 :(得分:2)
这似乎是杰克逊的一个错误...但是它的作者可能更有能力判断它是否是一个错误...如果你可以自由地改变杰克森看看genson {{3} }。
相当于enableDefaultTyping的Gensons是setUseRuntimeTypeForSerialization(不完全相同,但在大多数情况下它非常相似)。它在序列化期间使用运行时类型。这是一个例子:
Genson genson = new Genson.Builder().setUseRuntimeTypeForSerialization(true).create();
String json = genson.serialize(beforeResult);
System.out.println(json);
GenericType<Wrap<Integer[]>> type = new GenericType<Wrap<Integer[]>>() {};
Wrap<Integer[]> afterResult = genson.deserialize(json, type);
修改强> 如果你需要能够使用genson反序列化为多态或未知类型,请使用Genson.Builder的setWithClassMetadata(true)。此功能实际上仅用于json对象(无论它是否为抽象类)。
答案 1 :(得分:0)
我并不是100%确定确切的根本原因,但我怀疑这与Java类型擦除有关,以及传递泛型感知信息并将其与默认类型信息混合的问题。类型信息实际上仅基于非泛型类型;但是,它适用于特定类型的泛型类型(地图,集合)。
但是在这种情况下你有自定义泛型类型;而且我认为这是杰克逊无法为动态打字指明通用类型的属性的原因。
通常的解决方法是尽可能尝试进行子类化;但幸运的是,你能够找到更好的解决方法。