You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无法控制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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 06:45:01