如何从含null值与缺失属性的JSON生成模型及序列化器?
适配null值与缺失属性的JSON类模型实现方案
自动生成的序列化模型适配失败,核心原因是默认生成逻辑默认所有字段必填、且不接受null值,按以下两步改造即可兼容所有场景:
第一步:按字段实际存在规则声明类型
先提前梳理响应里的字段属性,不要全量声明为非空:
- 所有场景下都存在、不会返回null的字段,声明为非空必填类型
- 可能返回null、可能整体缺失的字段,统一声明为可空类型,不要用非空值类型接收
针对你给出的示例响应,字段规则非常明确:
- 根数组每个元素的
persone字段、persone.name字段是必传非空字段 persone.age、根级group字段既可能返回null,也可能在响应中缺失,必须声明为可空类型
不同技术栈的模型定义示例
C# (System.Text.Json)
// 根响应为 List<PersonEntry> 类型 public class PersonEntry { public PersonInfo Persone { get; set; } = null!; // 可空字符串,兼容缺失、null两种情况 public string? Group { get; set; } } public class PersonInfo { public string Name { get; set; } = null!; // 可空值类型,兼容null、缺失、合法整数三种情况 public int? Age { get; set; } }
Java (Jackson/Fastjson)
public class PersonEntry { private PersonInfo persone; private String group; // 字符串本身支持null赋值,无需额外包装 // 省略getter、setter } public class PersonInfo { private String name; // 用包装类Integer,不要用基本类型int,否则接收null会抛类型错误 private Integer age; // 省略getter、setter }
Dart/Flutter
class PersonEntry { final PersonInfo persone; // 可空类型,自动兼容缺失、null场景 final String? group; PersonEntry({required this.persone, this.group}); factory PersonEntry.fromJson(Map<String, dynamic> json) { return PersonEntry( persone: PersonInfo.fromJson(json['persone']), group: json['group'] as String?, ); } } class PersonInfo { final String name; final int? age; PersonInfo({required this.name, this.age}); factory PersonInfo.fromJson(Map<String, dynamic> json) { return PersonInfo( name: json['name'] as String, age: json['age'] as int?, ); } }
第二步:配置序列化器关闭缺失字段校验
自动生成的代码默认会开启「遇到未声明/缺失字段直接抛异常」的校验规则,需要手动修改全局序列化配置:
- System.Text.Json:初始化序列化配置时添加
UnmappedMemberHandling = JsonUnmappedMemberHandling.Skip,禁止设置为Disallow - Jackson:全局配置
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) - Fastjson:关闭
Feature.FailOnUnknownProperties特性 - Dart json_serializable:在模型类上添加注解
@JsonSerializable(disallowUnrecognizedKeys: false)
避坑说明
- 不要用非空值类型(int、bool、long、double等)接收可能为null的字段,必须用对应可空类型/包装类型,否则遇到null值会直接抛出类型转换异常
- 不要把「字段缺失」和「字段值为null」拆成两种逻辑处理,统一给可空字段赋值null即可,业务层统一判空就能同时兼容两种场景
- 除非业务有明确规则,不要给可空字段硬编码非空默认值(比如age缺失默认赋值0),否则会混淆「字段未传」和「字段值为默认值」的业务语义
内容的提问来源于stack exchange,提问作者Ayoub BOUMZEBRA
相关产品推荐
相关产品推荐

