无法控制JSON结构时如何用freezed联合类结合type+subtype做JSON序列化
Freezed双字段联合类JSON序列化实现方案
Freezed默认仅支持单字段作为Union分支判断依据,要实现type+subtype双字段联合判断,可通过自定义顶层fromJson分发逻辑实现,无需修改服务端返回结构:
1. 调整Field类定义
首先移除原有的unionKey配置,补全细粒度子类型,对应不同subtype的字段规则:
// 移除unionKey配置,改为自定义逻辑判断分支 @freezed class Field with _$Field { // 兜底通用类型,可选保留 const factory Field.generic({ String? name, String? type, String? subtype, dynamic value, }) = _FieldGeneric; // text类型子分支 const factory Field.textAutofill({ String? name, String? type, String? subtype, String? value, }) = _FieldTextAutofill; const factory Field.textPassword({ String? name, String? type, String? subtype, String? value, }) = _FieldTextPassword; // number类型子分支 const factory Field.numberInteger({ String? name, String? type, String? subtype, int? value, }) = _FieldNumberInteger; const factory Field.numberDouble({ String? name, String? type, String? subtype, double? value, }) = _FieldNumberDouble; // 注意:这里不使用默认生成的_$FieldFromJson,改为自定义实现 factory Field.fromJson(Map<String, dynamic> json) { final type = json['type'] as String?; final subtype = json['subtype'] as String?; // 双字段联合判断分支 switch(type) { case 'text': switch(subtype) { case 'autofill': return _FieldTextAutofill.fromJson(json); case 'password': return _FieldTextPassword.fromJson(json); default: return _FieldGeneric.fromJson(json); } case 'number': switch(subtype) { case 'integer': return _FieldNumberInteger.fromJson(json); case 'double': return _FieldNumberDouble.fromJson(json); default: return _FieldGeneric.fromJson(json); } default: return _FieldGeneric.fromJson(json); } } }
2. 上层类无需修改
原有的ExampleSuperclass定义保持不变,freezed会自动调用我们自定义的Field.fromJson方法完成列表元素的序列化。
3. 使用示例
序列化完成后可直接通过freezed的when方法匹配所有子类型,类型安全无需手动强转:
final example = ExampleSuperclass.fromJson(serverJson); example.fields?.forEach((field) { field.when( generic: (name, type, subtype, value) => print('未知类型字段:$name'), textAutofill: (name, type, subtype, value) => print('自动填充字段:$name, 值:$value'), textPassword: (name, type, subtype, value) => print('密码字段:$name, 值:$value'), numberInteger: (name, type, subtype, value) => print('整数字段:$name, 值:$value'), numberDouble: (name, type, subtype, value) => print('浮点数字段:$name, 值:$value'), ); });
该方案仅需要手动实现顶层分支分发逻辑,每个子类型的字段序列化仍然复用freezed自动生成的代码,无需手动处理字段映射,开发效率和类型安全性都可以得到保障。
内容的提问来源于stack exchange,提问作者Nico Rodsevich
相关产品推荐
相关产品推荐

