使用TypeReference的具有通用类型的JSON反序列化器

时间:2018-12-12 17:18:01

标签: java serialization jackson deserialization json-deserialization

我正在尝试推广这种方法:

public EventStream<Greeting> deserialize(String value){
    ObjectMapper mapper = new ObjectMapper();

    EventStream<Greeting> data = null;
    try {
        data = new ObjectMapper().readValue(value, new TypeReference<EventStream<Greeting>>() {});
    } catch (IOException e) {
        e.printStackTrace();
    }
    return data;
}

其中EventStream是:

public class EventStream<T> {

    private EventHeaders headers;

    @JsonDeserialize
    private T payload;
}

我想拥有的是在反序列化方法中,用泛型替换特定的Object Greeting。

我尝试过:

public <T> EventStream<T> deserialize(String value){
    ObjectMapper mapper = new ObjectMapper();

    EventStream<T> data = null;
    try {
        data = new ObjectMapper().readValue(value, new TypeReference<EventStream<T>>() {});
    } catch (IOException e) {
        e.printStackTrace();
    }
    return data;
}

但是EventStream结果内部的有效负载反序列化为LinkedHashMap。似乎TypeReference忽略了通用类型。 任何想法? 谢谢

1 个答案:

答案 0 :(得分:0)

您在这里遇到的是一个常见的问题,它是由类型擦除(java实现泛型的方式)引起的。

  

类型擦除可以解释为强制执行类型的过程   仅在编译时约束并丢弃元素类型   运行时的信息。 [1]

因此,当您尝试反序列化对象时,类型T是未知的,它仅被视为Object,反序列化结果将默认为MapLinkedHashMap准确地说。)

您可以通过将targetClass作为附加参数传递给函数调用来使方法通用,如下所示:

public <T> EventStream<T> deserialize(String value, Class<T> targetClass)

然后,您使用映射器的TypeFactory创建此targetClass的类型

JavaType type = mapper.getTypeFactory().constructParametricType(EventStream.class, targetClass);

您可以将其传递给readValue方法:

data = mapper.readValue(value, type);

完整代码:

public <T> EventStream<T> deserialize(String value, Class<T> targetClass){
    ObjectMapper mapper = new ObjectMapper();
    JavaType type = mapper.getTypeFactory()
        .constructParametricType(EventStream.class, targetClass);
    try {
        return mapper.readValue(value, type);
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}

[1] https://www.baeldung.com/java-type-erasure