JSON 使用 TypeReference 的泛型反序列化器

JSON deserializer with generic type using TypeReference

我正在尝试推广此方法:

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;
}

我想要的是在反序列化方法中用泛型替换特定的对象问候语。

我试过这个:

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 忽略了通用类型。 任何想法? 谢谢

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

Type erasure can be explained as the process of enforcing type constraints only at compile time and discarding the element type information at runtime. [1]

所以当你尝试反序列化你的对象时,类型 T 是未知的,它只是被视为 Object 并且反序列化结果将默认默认为 Map (LinkedHashMap 准确地说)。

您可以通过将您的 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