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

Flutter中Json序列化toJson方法缺失父抽象类type字段问题

子类toJson缺失父类type字段的原因及修复方案

问题核心

json_serializable默认不会自动将父类字段纳入子类的序列化输出,除非父类配置了完整的序列化逻辑,且子类显式合并父类的序列化结果。你的代码存在两个关键问题:

  1. 父类FormFieldModel仅添加了@JsonSerializable(createFactory: false)注解,但未定义抽象toJson方法,导致生成器无法为父类生成序列化逻辑,子类自然无法继承父类字段的序列化规则。
  2. 枚举FormFieldType未配置序列化注解,当前的反序列化逻辑依赖字符串拼接,不够简洁安全;同时序列化时会输出FormFieldType.text这类带前缀的字符串,不符合常规JSON格式。

修复步骤

  1. 给父类添加抽象toJson方法,让生成器生成父类字段的序列化逻辑
  2. 子类重写toJson时,合并父类与自身的序列化结果
  3. 给枚举添加@JsonEnum注解,优化序列化/反序列化行为
  4. 修正WizNumberField中写错的工厂方法名(原代码写成了GWizNumberField.fromJson)

修改后的完整代码

import 'package:json_annotation/json_annotation.dart';

part 'temp.g.dart';

// 配置枚举序列化时输出纯名称字符串(如'text'而非'FormFieldType.text')
@JsonEnum(valueField: 'name')
enum FormFieldType {
  text,
  number,
}

@JsonSerializable(createFactory: false)
abstract class FormFieldModel {
  final String label;
  final FormFieldType type;
  final bool isRequired;

  FormFieldModel({required this.label, required this.type, this.isRequired = true});

  // 新增抽象方法,触发生成器生成父类的toJson逻辑
  Map<String, dynamic> toJson();

  static FormFieldModel fromJson(Map<String, dynamic> json) {
    // 用byName替代原字符串拼接逻辑,更简洁安全
    final type = FormFieldType.values.byName(json['type']);

    switch (type) {
      case FormFieldType.text:
        return WizTextField.fromJson(json);
      case FormFieldType.number:
        return WizNumberField.fromJson(json);
    }
  }
}

@JsonSerializable()
class WizTextField extends FormFieldModel {
  final int? minLength;
  final int? maxLength;

  WizTextField({
    required String label,
    this.minLength,
    this.maxLength,
    bool isRequired = true,
  }) : super(label: label, type: FormFieldType.text, isRequired: isRequired);

  factory WizTextField.fromJson(Map<String, dynamic> json) => _$WizTextFieldFromJson(json);
  
  @override
  Map<String, dynamic> toJson() {
    // 合并父类与子类的序列化结果
    final parentJson = super.toJson();
    final childJson = _$WizTextFieldToJson(this);
    parentJson.addAll(childJson);
    return parentJson;
  }
}

@JsonSerializable()
class WizNumberField extends FormFieldModel {
  final int? min;
  final int? max;

  WizNumberField({
    required String label,
    this.min,
    this.max,
    bool isRequired = true,
  }) : super(label: label, type: FormFieldType.number, isRequired: isRequired);

  // 修正原代码中写错的工厂方法名
  factory WizNumberField.fromJson(Map<String, dynamic> json) => _$WizNumberFieldFromJson(json);
  
  @override
  Map<String, dynamic> toJson() {
    final parentJson = super.toJson();
    final childJson = _$WizNumberFieldToJson(this);
    parentJson.addAll(childJson);
    return parentJson;
  }
}

修复后生成的代码效果

运行dart run build_runner build后,生成器会为父类生成包含type、label、isRequired的序列化逻辑,子类仅生成自身字段的序列化代码,最终合并后的toJson输出会包含所有预期字段:

// 父类生成的序列化逻辑
Map<String, dynamic> _$FormFieldModelToJson(FormFieldModel instance) =>
    <String, dynamic>{
      'label': instance.label,
      'type': _$FormFieldTypeEnumMap[instance.type]!,
      'isRequired': instance.isRequired,
    };

const _$FormFieldTypeEnumMap = {
  FormFieldType.text: 'text',
  FormFieldType.number: 'number',
};

// 子类生成的序列化逻辑仅包含自身字段
Map<String, dynamic> _$WizNumberFieldToJson(WizNumberField instance) =>
    <String, dynamic>{
      'min': instance.min,
      'max': instance.max,
    };

内容的提问来源于stack exchange,提问作者Ouroboros

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 12:41:14