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);
我有一个看起来像这样的模型:
@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);