原生json序列化不处理继承、访问控制和类型元数据,导致多层继承下字段丢失;需三步解决:确认属性是否存在、确保可访问、改用支持继承的序列化机制。
原生 json 方法(如 javascript 的 json.stringify() 或 java 中未配置的 jackson 默认序列化)不识别类结构、不保留类型信息,也不处理继承链中的隐藏字段或父类私有成员。多层继承下属性丢失,本质是序列化器“只看运行时对象的可枚举自有属性”,而忽略继承关系、访问控制、泛型上下文和类型元数据。解决需分三步:明确哪些属性本该存在、确保它们在序列化前可被访问、用支持继承语义的机制替代原生调用。
确认属性是否实际存在于运行时对象上
原生 JSON.stringify() 只序列化对象自身的可枚举属性,不会遍历原型链;Java 中若字段为 private 且无 public getter,Jackson 默认也不会读取。因此第一步是验证:
- JavaScript:用
Object.getOwnPropertyNames(obj)和Object.getPrototypeOf(obj)检查属性是否真在实例上,还是仅定义在原型或父类构造函数中 - Java:检查字段是否被
private修饰,是否缺少对应 getter 方法;Lombok 的@Data在多层继承中需确保父类也加了注解,否则子类不会自动继承 getter - 常见陷阱:子类重写了父类字段但未调用
super()初始化,导致父类字段仍为null或默认值,序列化时被忽略(尤其在 Jackson 的非空策略下)
为继承结构显式启用类型识别与字段可见性
不能依赖“自动发现”。必须通过配置让序列化器理解类层级:
- Java(Jackson):在顶层抽象基类或接口上添加
@JsonTypeInfo和@JsonSubTypes,例如:@JsonTypeInfo(use = NAME, property = "@type")<br>@JsonSubTypes({@Type(SubA.class), @Type(SubB.class)})
同时确保每层父类字段都有 public getter 或标注@JsonProperty - JavaScript(如需模拟多态):手动扁平化继承链,用工具函数提取所有层级的自有+原型属性(注意不可枚举属性需特殊处理),再传给
JSON.stringify() - 避免字段被跳过:Jackson 中若字段为
transient、被@JsonIgnore标注、或在ObjectMapper配置中设置了SerializationFeature.WRITE_NULL_MAP_VALUES = false等,都可能导致看似“丢失”
替换原生序列化,改用支持继承的专用方案
原生方法天生不为面向对象设计。多层继承场景应放弃直接调用 JSON.stringify() 或 objectMapper.writeValueAsString(obj),转而使用:
- Java:用
TypeReference或带泛型参数的ObjectWriter处理嵌套继承集合;对复杂继承树,配合@JsonUnwrapped或自定义Serializer控制字段输出逻辑 - JavaScript:引入
class-transformer(配合reflect-metadata),通过plainToInstance()和instanceToPlain()显式维护类结构,支持装饰器标记继承字段 - 通用技巧:序列化前先将实例“规范化”——调用一个
toSerializable()方法,返回 plain object,该方法内部显式合并this、super层级的关键字段,不依赖自动反射
不复杂但容易忽略:属性没丢,只是原生方法根本没打算找它。











