如何用Jackson将第三方API可变JSON响应绑定到Java对象?
问题:Jackson适配第三方API的可变JSON响应
场景说明
第三方API返回两种JSON响应格式:
错误与成功数据混合的响应
{ "errorCount": 2, "errorIndices": [ 0, 1 ], "data": [ { "errorCode": 901, "errorMessage": "IBad data: Check the data", "errorData": "xxxx" }, { "errorCode": 901, "errorMessage": "IBad data: Check the data", "errorData": "XZY" }, "fun now" ] }
全成功场景下的响应
{"errorCount": 0,"errorIndices": [],"data": ["fun now","try later"]}
现有代码问题
当前定义的ApiResponse类仅能适配全成功场景,无法处理混合场景:
public class ApiResponse { @JsonProperty private int errorCount; @JsonProperty private int[] errorIndices; @JsonProperty private String[] data; // 省略其他代码...... }
适配两种场景的实现方向
方案1:使用Object[]接收data字段
将data字段类型改为Object[],借助Jackson自动类型推断能力,直接将数组元素分别解析为String或错误对象,再通过errorIndices区分数据类型:
public class ApiResponse { @JsonProperty private int errorCount; @JsonProperty private int[] errorIndices; @JsonProperty private Object[] data; // 辅助方法:提取成功数据 public List<String> getSuccessData() { List<String> successList = new ArrayList<>(); Set<Integer> errorIndexSet = new HashSet<>(Arrays.stream(errorIndices).boxed().toList()); for (int i = 0; i < data.length; i++) { if (!errorIndexSet.contains(i)) { successList.add((String) data[i]); } } return successList; } // 辅助方法:提取错误数据 public List<ErrorInfo> getErrorData() { List<ErrorInfo> errorList = new ArrayList<>(); Set<Integer> errorIndexSet = new HashSet<>(Arrays.stream(errorIndices).boxed().toList()); for (int i = 0; i < data.length; i++) { if (errorIndexSet.contains(i)) { errorList.add((ErrorInfo) data[i]); } } return errorList; } } // 错误信息实体类 public class ErrorInfo { @JsonProperty private int errorCode; @JsonProperty private String errorMessage; @JsonProperty private String errorData; // 构造器、getter、setter省略 }
该方案实现简单,无需额外配置,适合大部分场景。
方案2:自定义反序列化器
编写自定义JsonDeserializer,在解析data数组时,根据节点类型动态判断是字符串还是错误对象:
public class DataDeserializer extends JsonDeserializer<List<Object>> { @Override public List<Object> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { List<Object> result = new ArrayList<>(); JsonNode arrayNode = p.getCodec().readTree(p); if (arrayNode.isArray()) { for (JsonNode node : arrayNode) { if (node.isObject()) { ErrorInfo errorInfo = p.getCodec().treeToValue(node, ErrorInfo.class); result.add(errorInfo); } else if (node.isTextual()) { result.add(node.asText()); } } } return result; } }
在ApiResponse的data字段上指定该反序列化器:
public class ApiResponse { @JsonProperty private int errorCount; @JsonProperty private int[] errorIndices; @JsonProperty @JsonDeserialize(using = DataDeserializer.class) private List<Object> data; // 可根据业务需求添加数据提取方法 }
该方案灵活性更高,可自定义解析逻辑,适合复杂格式场景。
方案3:使用@JsonTypeInfo(不推荐)
若错误对象有固定标识字段(如errorCode),可尝试通过类型信息注解实现,但由于数组元素无统一父类标识,实现繁琐,不如前两种方案直观。
内容的提问来源于stack exchange,提问作者user1986244
相关产品推荐
相关产品推荐

