
本文详解如何在不修改目标类的前提下,通过 Jackson 自定义序列化器实现 @JsonValue 标注字段输出为无双引号的原始值(如 "1234" → 1234),并强调该操作本质脱离 JSON 规范,需谨慎用于非标准场景(如模板渲染、协议拼接等)。
本文详解如何在不修改目标类的前提下,通过 jackson 自定义序列化器实现 `@jsonvalue` 标注字段输出为无双引号的原始值(如 `"1234"` → `1234`),并强调该操作本质脱离 json 规范,需谨慎用于非标准场景(如模板渲染、协议拼接等)。
Jackson 的 @JsonValue 注解用于指定对象序列化时的“单一值代表”,其返回值仍遵循 JSON 数据类型规则:若返回 String,则必然以双引号包裹,这是 JSON 规范强制要求(RFC 8259),无法通过标准配置禁用引号。因此,objectMapper.writeValueAsString(new ValueType("1234")) 输出 "\"1234\""(即字符串 "1234")是完全合规且不可绕过的默认行为。
但若业务场景明确要求输出裸文本(例如生成 SQL 字面量、HTTP 查询参数、自定义协议片段等),可借助 自定义 JsonSerializer 实现可控的非标准序列化:
public class ValueTypeSerializer extends JsonSerializer<Scratch.ValueType> {
@Override
public void serialize(Scratch.ValueType value, JsonGenerator gen, SerializerProvider serializers)
throws IOException {
// 直接写入原始字符串值,跳过 JSON 字符串编码逻辑
gen.writeRawValue(value.toString()); // 前提:ValueType 重写了 toString() 返回内部 value
// 或更安全的方式(避免依赖 toString):
// gen.writeRawValue(((FieldAccessor) value).getValue()); // 需反射或构造器注入访问
}
}注册该序列化器(无需修改 ValueType 类):
使用 JSON Schema 验证 JSON 数据,从示例 JSON 生成 schema,并将其转换为 TypeScript 接口、Python 数据类或 Markdown 文档。
ObjectMapper objectMapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(Scratch.ValueType.class, new ValueTypeSerializer());
objectMapper.registerModule(module);
Scratch.ValueType valueType = new Scratch.ValueType("1234");
String plainValue = objectMapper.writeValueAsString(valueType);
System.out.println(plainValue); // 输出:1234(无引号)⚠️ 关键注意事项:
- 此输出不是合法 JSON,不能被标准 JSON 解析器(如
objectMapper.readValue(...))直接反序列化; -
writeRawValue()绕过了 Jackson 的类型安全校验,务必确保传入内容已做 XSS/SQL 注入等安全过滤; - 若
ValueType未提供toString()或安全访问value字段的途径,需通过反射(如AccessibleObject.setAccessible(true))获取私有字段,但会降低可维护性; - 更推荐的长期方案:重构使用场景——若需纯字符串,直接传
String;若需结构化数据,接受标准 JSON 格式;仅在遗留系统集成等强约束下才启用此非标序列化。
总之,Jackson 的设计哲学是“遵循规范优先”,所谓“去掉引号”实为放弃 JSON 语义。技术上可行,但应明确其代价,并在文档与团队中同步该非标准行为。

















