如何处理返回不同成功/失败响应的老旧第三方REST API?
这种场景我之前处理过好多次,核心问题在于你试图用一个WrapperBean去适配两种完全不同结构的响应——这就是为什么会抛出ClassCastException的原因,不管是Jackson还是Gson,都没法把结构差异这么大的JSON强行转成同一个Bean。
正确的思路是先判断响应的结构类型,再针对性解析,下面我用Java+Jackson(最常用的序列化库)给你写一套完整的处理示例:
第一步:定义对应响应的实体类
先分别把成功和失败的响应结构映射成独立的实体类,避免结构冲突:
// 成功响应实体类,根据API实际的嵌套结构定义字段 public class SuccessResObj { // 示例字段,替换成你实际的10-15个嵌套对象 private String requestId; private UserProfile userProfile; private OrderSummary orderSummary; // 嵌套类示例,根据API结构补充 public static class UserProfile { private String userId; private String fullName; private ContactInfo contactInfo; } public static class ContactInfo { private String phone; private String email; } public static class OrderSummary { private String orderNo; private BigDecimal totalAmount; private List<OrderItem> items; } public static class OrderItem { private String sku; private int quantity; } // 省略所有字段的getter/setter、全参/无参构造方法 } // 失败响应实体类,严格匹配API返回的结构 public class FailureResObj { private String status; private int code; // API固定返回400 // 省略getter/setter、构造方法 }
第二步:核心响应处理逻辑
先把API返回的字符串转成通用的JsonNode,通过判断字段特征区分成功/失败响应,再分别解析成对应的实体类,最后存入数据库:
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.jdbc.core.JdbcTemplate; // 示例用JdbcTemplate,你可以换成JPA/MyBatis public class ThirdPartyApiHandler { private final ObjectMapper objectMapper = new ObjectMapper(); private final JdbcTemplate jdbcTemplate; // 注入数据库操作类 // 构造方法注入依赖 public ThirdPartyApiHandler(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } public void processApiResponse(String apiResponseJson) throws Exception { // 先转成JsonNode,避免提前强转出错 JsonNode rootNode = objectMapper.readTree(apiResponseJson); // 判断是否为失败响应:API失败时固定返回code=400 if (rootNode.has("code") && rootNode.get("code").asInt() == 400) { FailureResObj failureRes = objectMapper.treeToValue(rootNode, FailureResObj.class); saveFailureResponse(failureRes); } else { // 解析成功响应 SuccessResObj successRes = objectMapper.treeToValue(rootNode, SuccessResObj.class); saveSuccessResponse(successRes); } } // 保存失败响应到数据库 private void saveFailureResponse(FailureResObj failureRes) { String sql = "INSERT INTO api_failure_log (status, code, create_time) VALUES (?, ?, NOW())"; jdbcTemplate.update(sql, failureRes.getStatus(), failureRes.getCode()); } // 保存成功响应到数据库(嵌套对象需要拆分存入对应表,这里只做示例) private void saveSuccessResponse(SuccessResObj successRes) { // 先保存主记录 String mainSql = "INSERT INTO api_success_log (request_id, user_id, order_no, total_amount, create_time) VALUES (?, ?, ?, ?, NOW())"; jdbcTemplate.update(mainSql, successRes.getRequestId(), successRes.getUserProfile().getUserId(), successRes.getOrderSummary().getOrderNo(), successRes.getOrderSummary().getTotalAmount()); // 再保存嵌套的订单明细 String itemSql = "INSERT INTO api_order_items (order_no, sku, quantity) VALUES (?, ?, ?)"; for (SuccessResObj.OrderItem item : successRes.getOrderSummary().getItems()) { jdbcTemplate.update(itemSql, successRes.getOrderSummary().getOrderNo(), item.getSku(), item.getQuantity()); } } }
补充说明
为什么不用WrapperBean?
如果强行用一个同时包含SuccessResObj和FailureResObj字段的WrapperBean,当API返回成功响应时,失败相关的字段会是null,但如果API响应结构和WrapperBean不匹配(比如成功响应里没有code字段),序列化库可能直接抛出解析异常,不如先判断结构再解析稳妥。如果用Gson处理怎么办?
逻辑和Jackson完全一致,只是把ObjectMapper换成Gson,JsonNode换成JsonElement:import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; public void processWithGson(String apiResponseJson) { JsonElement jsonElement = JsonParser.parseString(apiResponseJson); JsonObject rootObj = jsonElement.getAsJsonObject(); if (rootObj.has("code") && rootObj.get("code").getAsInt() == 400) { FailureResObj failureRes = new Gson().fromJson(jsonElement, FailureResObj.class); saveFailureResponse(failureRes); } else { SuccessResObj successRes = new Gson().fromJson(jsonElement, SuccessResObj.class); saveSuccessResponse(successRes); } }注意事项
- 确保判断条件的准确性:如果API失败时还有其他
code值,需要调整判断逻辑(比如判断是否同时存在status和code字段)。 - 嵌套对象的字段要和API返回的完全匹配,字段名不匹配时可以用
@JsonProperty(Jackson)或@SerializedName(Gson)注解映射。 - 如果用Spring的
RestTemplate调用API,建议直接获取ResponseEntity<String>,避免提前指定泛型导致转换失败。
- 确保判断条件的准确性:如果API失败时还有其他
内容的提问来源于stack exchange,提问作者shrikant.sharma
相关产品推荐
相关产品推荐

