
本文介绍如何通过 @JsonCreator 和 @JsonProperty 注解,在不手动解析的前提下,将形如 "field3": {"type": {...}} 的嵌套 JSON 自动扁平化为 "field3": {...} 结构,并完成反序列化。
本文介绍如何通过 `@jsoncreator` 和 `@jsonproperty` 注解,在不手动解析的前提下,将形如 `"field3": {"type": {...}}` 的嵌套 json 自动扁平化为 `"field3": {...}` 结构,并完成反序列化。
在使用 Jackson 处理外部 API 或遗留系统返回的 JSON 时,常会遇到“过度嵌套”的结构(例如字段值本身是一个仅含 type 单键的对象),而业务逻辑更期望直接访问内层属性。此时,若拒绝编写冗余的中间转换逻辑,可借助 Jackson 的构造器反序列化机制优雅解决。
核心思路是:为嵌套目标类(如 Field3Class)定义一个带 @JsonCreator 的构造方法,并通过 @JsonProperty("type") 显式绑定其内部对象,再在构造中提取并赋值给本类字段。Jackson 会自动将 JSON 中 "field3" 对应的整个对象(即 { "type": { "f1":"v1", "f2":"v2" } })传入该构造器,而非默认按字段名匹配。
以下为完整可运行示例:
import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
public class Flattened implements Serializable {
private static final ObjectMapper objectMapper = new ObjectMapper();
public String field1;
public String field2;
public Field3Class field3;
public static void main(String[] args) throws IOException {
String json = """
{
"field1":"value1",
"field2":"value2",
"field3": {
"type": {
"f1":"v1",
"f2":"v2"
}
}
}
""";
Flattened result = objectMapper.readValue(json, Flattened.class);
System.out.println(objectMapper.writeValueAsString(result));
// 输出: {"field1":"value1","field2":"value2","field3":{"f1":"v1","f2":"v2"}}
}
@JsonInclude(JsonInclude.Include.NON_NULL)
public static class Field3Class implements Serializable {
public String f1;
public String f2;
@JsonCreator
public Field3Class(@JsonProperty("type") Type type) {
if (type != null) {
this.f1 = type.f1;
this.f2 = type.f2;
}
}
// 内部类型仅用于反序列化桥梁,无需暴露给上层
public static class Type implements Serializable {
public String f1;
public String f2;
}
}
}
✅ 关键要点说明:
- @JsonCreator 标记的构造器必须是 public 或 protected,且参数需用 @JsonProperty("xxx") 明确指定来源字段名;
- Jackson 会将 JSON 中与构造器参数名(或 @JsonProperty 值)匹配的整个子对象注入,而非尝试拆解字段;
- 若嵌套结构可能为 null,建议在构造器中添加空值检查(如示例所示),避免 NullPointerException;
- 此方案完全基于注解驱动,无需自定义 Deserializer、Module 或运行时修改 ObjectMapper 配置,符合“零侵入”设计诉求。
⚠️ 注意:该方式适用于已知固定嵌套层级与键名的场景(如本例中 field3.type)。若嵌套路径动态多变(如 field3.data.payload 或存在多个同级包装键),则需考虑编写专用 JsonDeserializer 或预处理 JSON 字符串。










