
当使用 jackson 的 `objectmapper.writevalue()` 直接序列化一个已格式化的 json 字符串时,objectmapper 会将其视为 java 字符串对象并输出为合法 json 字符串(即加引号、转义内部双引号),导致双重 json 化。正确做法是直接写入原始字符串,或序列化结构化数据(如 map 或 pojo)。
在使用 Jackson 处理 JSON 数据时,一个常见误区是将已格式化的 JSON 字符串(例如 "{"test":"mytest/123"}")直接传给 ObjectMapper.writeValue(...) 方法。此时,ObjectMapper 并不会“解析并重写”该字符串,而是严格遵循 JSON 规范,将整个 Java String 对象序列化为一个 JSON 字符串值——这意味着:
- 输出必须以 " 开头和结尾;
- 字符串中所有 " 都需转义为 \";
- 反斜杠 \ 等特殊字符也会被转义。
因此,输入 "{\"test\":\"mytest/123\"}" 经 writeValue() 序列化后,实际输出为:
"{\"test\":\"mytest/123\"}"(注意:外层引号 + 内部所有引号均被转义)
✅ 正确解决方案如下:
✅ 方案一:绕过 ObjectMapper,直接写入原始字符串
若你已拥有合法 JSON 字符串且无需 Jackson 处理,最简单高效的方式是跳过序列化环节:
OutputStream outputStream = new PrintStream(System.out);
String output = "{\"test\":\"mytest/123\"}";
outputStream.write(output.getBytes(StandardCharsets.UTF_8));
outputStream.write('\n'); // 可选:换行
outputStream.flush();⚠️ 注意:避免使用 PrintStream.println(String)(可能引入平台相关换行符或编码问题),推荐显式指定 UTF-8 编码并手动控制换行。
✅ 方案二:序列化结构化数据(推荐)
让 Jackson 负责 JSON 构建,而非传入“伪 JSON 字符串”。使用 Map、JsonNode 或自定义 POJO:
ObjectMapper mapper = new ObjectMapper(); Mapdata = Map.of("test", "mytest/123"); mapper.writeValue(System.out, data); // 输出:{"test":"mytest/123"}
或使用 POJO(更类型安全、可扩展):
public static class Response {
private final String test;
public Response(String test) { this.test = test; }
public String getTest() { return test; }
}
// 使用
Response response = new Response("mytest/123");
mapper.writeValue(System.out, response); // 同样输出:{"test":"mytest/123"}❌ 错误模式(应避免)
// 危险!人为拼接 JSON 字符串 + 用 writeValue 序列化 → 双重 JSON 化
String badJson = "{\"test\":\"value\"}";
mapper.writeValue(out, badJson); // → "{\\"test\\":\\"value\\"}"? 补充说明
- writeValueAsString() 和 writeValue() 行为一致:都执行完整序列化逻辑;
- 若需动态构建复杂 JSON,可考虑 ObjectMapper.valueToTree() + JsonNode 操作;
- 所有 writeValue* 方法默认启用 JsonGenerator.Feature.ESCAPE_NON_ASCII 等安全特性,不可通过配置禁用字符串转义——因为这是 JSON 标准强制要求。
总之:不要把 JSON 字符串当作 JSON 数据传给 ObjectMapper;要传数据结构,让 Jackson 生成 JSON。 这既是规范做法,也能彻底规避意外转义问题。










