
本文详解如何正确处理 JSON 中嵌套 JSON 字符串(即外层 JSON 的某个字段值本身是转义后的 JSON 字符串)的反序列化问题,重点解决因字符串转义不足导致的 JsonParseException 异常。
本文详解如何正确处理 json 中嵌套 json 字符串(即外层 json 的某个字段值本身是转义后的 json 字符串)的反序列化问题,重点解决因字符串转义不足导致的 `jsonparseexception` 异常。
在实际开发中,尤其是对接遗留系统或第三方 API 时,常会遇到一种特殊结构:外层 JSON 的某个字段(如 "errormessage")的值并非普通字符串,而是一个被双引号包裹、且内部已做 JSON 转义的 JSON 字符串。这种“JSON-in-String”结构若未被正确认知和处理,使用 Jackson 直接反序列化为 POJO 将必然失败——典型错误如 Unexpected character ('t' (code 116)),本质是 Jackson 尝试将已转义的字符串误当作原始 JSON 对象解析,导致语法解析中断。
问题根源:字符串字面量 vs. 实际 JSON 结构
观察原始输入:
{"errormessage":"{"timestamp":"2021-10-19T07:57:35.205+0000",...}"}此处 "errormessage" 的值是一个 Java 字符串字面量,其内容是 JSON 文本,但该文本中的双引号、反斜杠等字符在 Java 源码中必须被正确转义,才能被 ObjectMapper 在运行时识别为“一段合法的 JSON 字符串”,而非非法的 JSON 片段。
常见误区是直接复制粘贴原始 JSON 到 Java 字符串中,忽略 Java 字符串字面量的转义规则。例如:
// ❌ 错误:未对内层 JSON 的引号进行 Java 层转义
final String nestedErrorResponse = "{"errormessage":"{"timestamp":"2021-10-19T..."}"}";
// ↑ 此处第二个 { 前的 " 会提前结束字符串,编译即报错正确做法:双重转义(Java 字符串 + JSON 字符串)
要使 Jackson 成功将 errormessage 字段值作为纯字符串读取(而非尝试解析其内部结构),需确保该字段在 JSON 字符串中是合法的字符串值。这意味着:
- 内层 JSON 的所有双引号 " 必须在 Java 字符串中表示为 ";
- 而每个 " 在最终传递给 Jackson 的字符串中,应表现为一个真实的 " 字符(即 Java 解析后还原为 JSON 所需的引号)。
因此,Java 字符串字面量中需写成 " —— 第一个 用于转义第二个 ,使其成为字面量 ,随后 " 才能被 Java 解析为一个 " 字符,最终构成 JSON 合法字符串。
✅ 正确示例(含完整转义):
final String nestedErrorResponse =
"{"errormessage":"{\"timestamp\":\"2021-10-19T07:57:35.205+0000\",\"status\":400,\"error\":\"Bad Request\",\"message\":\"Bad Request: xxxx xx is xx xxx. path=/xxx/verify\",\"path\":\"/xxx/xxx\"}"}";
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new Jdk8Module());
TransferResponse response = objectMapper.readValue(nestedErrorResponse, TransferResponse.class);
// 此时 response.getMessage().orElse("") 将返回完整的内层 JSON 字符串? 提示:使用 IntelliJ IDEA 等现代 IDE 时,可直接粘贴原始 JSON 到字符串中,IDE 会自动补全所需转义符(如将 " 替换为 "),大幅提升准确性与效率。
进阶方案:自动解析嵌套 JSON(按需)
若业务需要进一步将 errormessage 中的 JSON 字符串二次解析为结构化对象(如 ErrorResponseDetail),可结合 Jackson 的 @JsonDeserialize 自定义反序列化器,或采用两步解析:
// 第一步:读取为通用 Map 或 JsonNode
JsonNode rootNode = objectMapper.readTree(nestedErrorResponse);
String errorMessageJson = rootNode.path("errormessage").asText();
// 第二步:解析嵌套 JSON
ErrorResponseDetail detail = objectMapper.readValue(errorMessageJson, ErrorResponseDetail.class);此方式解耦清晰,避免 POJO 层强耦合嵌套逻辑,推荐用于结构多变或需条件解析的场景。
注意事项与最佳实践
- ✅ 始终校验输入 JSON 合法性:使用在线工具(如 jsonlint.com)验证原始 JSON 是否格式正确;
- ✅ 优先使用 JsonNode 处理不确定结构:比强类型 POJO 更健壮;
- ⚠️ 避免手动拼接 JSON 字符串:易出错,推荐用 ObjectMapper.writeValueAsString() 生成;
- ✅ 启用 DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES = false:提升对非标响应的容错能力;
- ? 敏感字段脱敏处理:如示例中的 xxxx,应在日志或调试输出前清理,防止信息泄露。
通过理解 JSON 字符串在 Java 源码中的双重语义(字符串字面量 vs. 运行时 JSON 内容),并严格遵循转义规范,即可稳健应对各类嵌套 JSON 反序列化挑战。










