使用 ObjectMapper 映射修剪后的响应或包装获得的响应
Mapping a trimmed response using ObjectMapper Or wrapping the response obtained
详情---
我的一个 POJO SomeResponseObject
的 api 响应具有属性
@JsonProperty("s_summary")
private Map<String, SummaryObject> summary
它还有更多的属性。这些在 json
中总结如下:
{
"s_summary": {
"rewardSubscription": {
"accountId": "XYZ",
"startDate": "2015-12-29T19:00:00+05:30",
"endDate": "2017-06-21T00:00:00+05:30",
"isActive": true,
"entityId": "ID123",
"status": "ACTIVE"
}
}
}
此 POJO(json) 由我们的服务进一步修改为 return 响应为:
{
"rewardSubscription": {
"accountId": "XYZ",
"startDate": "2015-12-29T19:00:00+05:30",
"endDate": "2017-06-21T00:00:00+05:30",
"isActive": true,
"entityId": "ID123",
"status": "ACTIVE"
}
}
缩小范围---
现在我们正在针对此 API 调用编写测试。我们最终无法将响应映射到任何特定的 POJO(java 响应 class)。 测试代码-
JSONObject responseObject = new JSONObject(responseFromService.getResponseBody())
.getJSONObject("RESPONSE");
ObjectMapper objectMapper = new ObjectMapper();
SomeResponseObject summaryResponse = objectMapper.getObjectMapper()
.readValue(responseObject.toString(), SomeResponseObject.class); // And this wouldn't work.
问题--
有什么方法可以转换当前的 API 响应或以某种方式将其包装以映射到实际的 POJO(SomeResponseObject.class
)?
提前致谢。
问题
您收到一个带有 rewardSubscription
字段的对象,或者,在您的情况下,是一张带有 rewardSubscription
键的地图。您不能将地图直接转换为 SomeResponseObject 类型的对象。
解决方案
选项 1
手动将 json 转换为地图并将其设置为 SomeResponseObject 实例:
JSONObject responseObject = new JSONObject(responseFromService.getResponseBody())
.getJSONObject("RESPONSE");
ObjectMapper objectMapper = new ObjectMapper();
Map<String, SummaryObject> summaryMap = objectMapper.readValue(responseObject.toString(), new TypeReference<Map<String, SummaryObject>>() {});
SomeResponseObject response = new SomeResponseObject();
response.setSummaryMap(summaryMap);
选项 2
为了避免每次都手动转换地图,请编写一个 custom deserializer 来处理这两种情况。 deserialize
方法应该与此类似:
@Override
public SomeResponseObject deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
JsonNode rootNode = jp.readValueAsTree();
JsonNode sSummaryNode = rootNode.get("s_summary");
if (sSummaryNode != null) {
// Usual case.
return objectMapper.treeToValue(sSummaryNode, SomeResponseObject.class);
} else {
// Special case - when received a map.
Map<String, SummaryObject> summaryMap = objectMapper.readValue(rootNode.toString(), new TypeReference<Map<String, SummaryObject>>() {});
SomeResponseObject response = new SomeResponseObject();
response.setSummaryMap(summaryMap);
return response;
}
}
然后在你不关心的代码中:
ObjectMapper objectMapper = new ObjectMapper();
SomeResponseObject response = objectMapper.readValue(json, SomeResponseObject.class);
详情---
我的一个 POJO SomeResponseObject
的 api 响应具有属性
@JsonProperty("s_summary")
private Map<String, SummaryObject> summary
它还有更多的属性。这些在 json
中总结如下:
{
"s_summary": {
"rewardSubscription": {
"accountId": "XYZ",
"startDate": "2015-12-29T19:00:00+05:30",
"endDate": "2017-06-21T00:00:00+05:30",
"isActive": true,
"entityId": "ID123",
"status": "ACTIVE"
}
}
}
此 POJO(json) 由我们的服务进一步修改为 return 响应为:
{
"rewardSubscription": {
"accountId": "XYZ",
"startDate": "2015-12-29T19:00:00+05:30",
"endDate": "2017-06-21T00:00:00+05:30",
"isActive": true,
"entityId": "ID123",
"status": "ACTIVE"
}
}
缩小范围---
现在我们正在针对此 API 调用编写测试。我们最终无法将响应映射到任何特定的 POJO(java 响应 class)。 测试代码-
JSONObject responseObject = new JSONObject(responseFromService.getResponseBody())
.getJSONObject("RESPONSE");
ObjectMapper objectMapper = new ObjectMapper();
SomeResponseObject summaryResponse = objectMapper.getObjectMapper()
.readValue(responseObject.toString(), SomeResponseObject.class); // And this wouldn't work.
问题--
有什么方法可以转换当前的 API 响应或以某种方式将其包装以映射到实际的 POJO(SomeResponseObject.class
)?
提前致谢。
问题
您收到一个带有 rewardSubscription
字段的对象,或者,在您的情况下,是一张带有 rewardSubscription
键的地图。您不能将地图直接转换为 SomeResponseObject 类型的对象。
解决方案
选项 1
手动将 json 转换为地图并将其设置为 SomeResponseObject 实例:
JSONObject responseObject = new JSONObject(responseFromService.getResponseBody())
.getJSONObject("RESPONSE");
ObjectMapper objectMapper = new ObjectMapper();
Map<String, SummaryObject> summaryMap = objectMapper.readValue(responseObject.toString(), new TypeReference<Map<String, SummaryObject>>() {});
SomeResponseObject response = new SomeResponseObject();
response.setSummaryMap(summaryMap);
选项 2
为了避免每次都手动转换地图,请编写一个 custom deserializer 来处理这两种情况。 deserialize
方法应该与此类似:
@Override
public SomeResponseObject deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
JsonNode rootNode = jp.readValueAsTree();
JsonNode sSummaryNode = rootNode.get("s_summary");
if (sSummaryNode != null) {
// Usual case.
return objectMapper.treeToValue(sSummaryNode, SomeResponseObject.class);
} else {
// Special case - when received a map.
Map<String, SummaryObject> summaryMap = objectMapper.readValue(rootNode.toString(), new TypeReference<Map<String, SummaryObject>>() {});
SomeResponseObject response = new SomeResponseObject();
response.setSummaryMap(summaryMap);
return response;
}
}
然后在你不关心的代码中:
ObjectMapper objectMapper = new ObjectMapper();
SomeResponseObject response = objectMapper.readValue(json, SomeResponseObject.class);