使用Rest Client和Object Mapper反序列化JSON字符串问题
问题原因分析
外部API返回的是被JSON字符串包裹的JSON对象(双重序列化结果):外层是一个JSON字符串值,内部才是ApiResponse对应的标准JSON结构。当你直接尝试将返回值反序列化为ApiResponse时,Jackson会把整个外层字符串当作输入,但你的实体类没有接收String类型参数的构造方法,因此抛出no String-argument constructor/factory method异常。
解决方案
方案1:两次反序列化(最直接)
先解析外层字符串得到内部纯JSON内容,再将内容反序列化为实体类:
String responseBody = restClient.post() .uri(url) .contentType(MediaType.APPLICATION_JSON) .body(request.toJsonString()) .retrieve() .body(String.class); ApiResponse response; try { // 第一步:解析外层字符串,获取内部纯JSON文本 String innerJson = objectMapper.readValue(responseBody, String.class); // 第二步:将纯JSON文本解析为实体类 response = objectMapper.readValue(innerJson, ApiResponse.class); } catch (IOException e) { throw new RuntimeException("反序列化失败", e); } return response;
方案2:借助JsonNode处理
先把返回内容读成JsonNode,再提取内部文本内容完成反序列化:
String responseBody = restClient.post() .uri(url) .contentType(MediaType.APPLICATION_JSON) .body(request.toJsonString()) .retrieve() .body(String.class); ApiResponse response; try { JsonNode textNode = objectMapper.readTree(responseBody); // 提取文本节点内容,解析为实体类 response = objectMapper.readValue(textNode.asText(), ApiResponse.class); } catch (IOException e) { throw new RuntimeException("反序列化失败", e); } return response;
方案3:RestClient链式处理(简化版)
通过map方法直接在RestClient调用链中完成两次转换:
ApiResponse response = restClient.post() .uri(url) .contentType(MediaType.APPLICATION_JSON) .body(request.toJsonString()) .retrieve() .body(String.class) .map(outerJson -> { try { String innerJson = objectMapper.readValue(outerJson, String.class); return objectMapper.readValue(innerJson, ApiResponse.class); } catch (IOException e) { throw new RuntimeException("反序列化失败", e); } });
额外注意
你的ApiResponse类中number字段定义为String,但外部API返回的是数字类型1,Jackson默认会自动完成数字到字符串的转换,无需额外处理;如果后续遇到类型不兼容的情况,可以添加@JsonFormat或自定义反序列化器调整。
内容的提问来源于stack exchange,提问作者Gonzalo Martinez
相关产品推荐
相关产品推荐

