Flutter+Freezed:含抽象类的类无法生成fromJson方法问题
解决Freezed中包含抽象类成员的序列化问题
问题根源
当你在Freezed类ModelGroup中使用抽象类IModel作为成员类型时,Freezed依赖的json_serializable无法自动处理抽象类型的反序列化——因为抽象类不能被实例化,序列化器不知道该把JSON数据转换成哪个具体的IModel实现类,因此会报错无法生成fromJson方法。
解决方案
方案一:通过类型鉴别符+自定义转换器处理抽象类序列化
适用于IModel有多个实现类的场景,核心是给每个实现类添加类型标识,再通过转换器根据标识匹配具体类:
- 给IModel实现类添加类型标识
修改Model类,添加固定的type字段标记当前类类型:
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:json_annotation/json_annotation.dart'; part 'model.freezed.dart'; part 'model.g.dart'; abstract class IModel { String getModelId(); } @freezed class Model with _$Model implements IModel { const Model._(); const factory Model({ required String id, // 默认值设为当前类的标识,序列化时自动携带 @Default('model') String type, }) = _Model; factory Model.fromJson(Map<String, Object?> json) => _$ModelFromJson(json); @override String getModelId() { return id; } }
- 创建IModel的Json转换器
编写转换器类,根据type字段将JSON转换为对应IModel实现类:
import 'package:json_annotation/json_annotation.dart'; import 'model.dart'; class IModelConverter implements JsonConverter<IModel, Map<String, dynamic>> { const IModelConverter(); @override IModel fromJson(Map<String, dynamic> json) { final type = json['type'] as String; switch (type) { case 'model': return Model.fromJson(json); // 后续新增IModel实现类时,添加对应case分支 default: throw ArgumentError('无法识别的IModel类型: $type'); } } @override Map<String, dynamic> toJson(IModel object) { if (object is Model) { return object.toJson(); } throw ArgumentError('不支持的IModel类型'); } }
- 在ModelGroup中使用转换器
给models字段标注自定义转换器,让Freezed知晓如何处理抽象类型:
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:json_annotation/json_annotation.dart'; import 'model.dart'; import 'i_model_converter.dart'; part 'model_group.freezed.dart'; part 'model_group.g.dart'; @freezed class ModelGroup with _$ModelGroup { const factory ModelGroup({ // 用自定义转换器标注抽象类成员 @IModelConverter() required List<IModel> models, }) = _ModelGroup; factory ModelGroup.fromJson(Map<String, Object?> json) => _$ModelGroupFromJson(json); }
- 重新生成序列化代码
运行build_runner命令更新自动生成的代码:
flutter pub run build_runner build
方案二:直接使用具体类型(仅适用于单一实现场景)
如果IModel目前只有Model这一个实现类,可直接将ModelGroup中的List<IModel>改为List<Model>,Freezed会自动生成正确的序列化方法:
@freezed class ModelGroup with _$ModelGroup { const factory ModelGroup({ required List<Model> models, }) = _ModelGroup; factory ModelGroup.fromJson(Map<String, Object?> json) => _$ModelGroupFromJson(json); }
内容的提问来源于stack exchange,提问作者BrML
相关产品推荐
相关产品推荐

