Jackson Generic Type References + enableDefaultTyping问题

时间:2012-10-24 19:32:33

标签: java json generics jackson

在使用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

[编辑] 使用地图而不是数据作为包装对象按预期工作!

2 个答案:

答案 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类型擦除有关,以及传递泛型感知信息并将其与默认类型信息混合的问题。类型信息实际上仅基于非泛型类型;但是,它适用于特定类型的泛型类型(地图,集合)。

但是在这种情况下你有自定义泛型类型;而且我认为这是杰克逊无法为动态打字指明通用类型的属性的原因。

通常的解决方法是尽可能尝试进行子类化;但幸运的是,你能够找到更好的解决方法。