Jackson - 将 json 反序列化为通用类型

Jackson - deserialize json into generic type

我有一个看起来像这样的模型:

@JsonIgnoreProperties(ignoreUnknown = true)
public class InputMessage<T> {

    @JsonProperty("UUID")
    private String UUID;

    @JsonProperty("MessageType")
    private String messageType;

    @JsonProperty("KeyData")
    private T keyData;

    ...

    getters/setters
}

这将位于一个可从任意客户端调用的库中,因此 KeyData 字段具有通用类型。如果我尝试从客户端代码进行如下调用,我会收到 ClassCastException java.lang.ClassCastException: class java.util.LinkedHashMap cannot be cast to class model.KeyData:


编辑

尝试使用 constructParametricType() 建议,但总是出错。

ObjectMapper objectMapper = new ObjectMapper();
JavaType type = objectMapper.getTypeFactory().constructParametricType(InputMessage.class, KeyData.class);
KeyData keyData = objectMapper.readValue(inputMessage.getKeyData().toString(), type);

我试图反序列化的 json 看起来像这样:

{
  UUID: 9bae9a6a-5553-4716-8a85-995f36df7732,
  KeyData: {
    CNSM_ID: 2,
    LGCY_SRC_ID: 123,
    PARTN_NBR: 1,
    PCD_EFF_DT: 2019-01-01,
    SRC_CD: AB
  },
  MessageType: provider_selection,
  Partition: 3,
  Rows: [
    {
      Type: l_cov_prdt_pcd_w_srch,
      SchemaID: 2,
      Value: base64encoded value
    }
  ]
}

我用来反序列化 json 的库是 com.fasterxml.jackson.core:jackson-databind:2.9.8

如有任何帮助,我们将不胜感激。

当您将 JSON 反序列化为泛型 class 时,Jackson 无法猜测所使用的泛型类型,因为那不是 JSON.
中存在的信息 当它不知道如何反序列化一个字段时,它会使用 java.util.LinkedHashMap 作为目标。

你想要的是一个通用类型,例如:

InputMessage<KeyData> inputMessage = ...;
KeyData keyData = inputMessage.getKeyData();

一种优雅的解决方法是通过指定预期的泛型为 class 定义 Jackson JavaType
TypeFactory.constructParametricType(Class parametrized, Class... parameterClasses) 允许。

假设你想反序列化为InputMessage<KeyData>,你可以这样做:

JavaType type = mapper.getTypeFactory().constructParametricType(InputMessage.class, KeyData.class);
InputMessage<KeyData> keyData = mapper.readValue(json, type);

关于您的评论:

The library code with the generic type knows nothing about the KeyData class, so I assume it belongs in the client code?

库不需要知道这个 class 但是客户端应该传递 class 以正确执行反序列化并 return 一个通用实例给客户端而不是原始类型。

例如,客户可以这样使用库:

InputMessage<KeyData> inputMessage = myJsonLibrary.readValue("someValueIfNeeded", KeyData.class);