0

我在使用 enableDefaultTyping 和提供泛型 TypeReference 时遇到了反序列化问题。杰克逊似乎无法决定哪种类型的信息更重要。这个测试用例证明了这个问题:

@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 = 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 而不是 TypeReference 可以省略该问题,但这仍然不是首选行为。

为了解决这个问题,我是否错过了任何一种选择?

我使用的是杰克逊 1.9.3

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

4

2 回答 2

2

这似乎是杰克逊的一个错误......但是它的作者可能更有能力判断它是否是一个错误......如果你可以自由地改变杰克逊,看看 genson http://code.google .com/p/genson/

Gensons 等效于 enableDefaultTyping 是 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 对象(不管它是否是抽象类)。

于 2012-10-24T22:19:39.350 回答
0

我不是 100% 确定确切的根本原因,但我怀疑这与 Java 类型擦除有关,以及传递泛型感知信息并将其与默认类型信息混合的问题。类型信息实际上只基于非泛型类型;但是,它确实适用于特定种类的泛型类型(地图、集合)。

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

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

于 2012-10-25T15:59:34.983 回答