Dart中如何序列化抽象类AnimationDecorationInstance的列表为JSON?
Dart抽象类列表的JSON序列化解决方案
问题场景
需要将抽象类型AnimationDecorationInstance的列表序列化为JSON,用于定义屏幕动画集合。列表中包含TextEffect、FilterEffect等不同子类实例,通过AnimationDecorationType枚举区分类型,但使用json_annotation生成代码时出现错误,提示无法为抽象类生成fromJson代码。
现有代码
import 'package:json_annotation/json_annotation.dart'; part 'animation_decoration.g.dart'; @JsonEnum() enum AnimationDecorationType { text, filter } @JsonSerializable(explicitToJson: true) abstract class AnimationDecorationInstance { get getArtifactDecorationType; } @JsonSerializable(explicitToJson: true) class AnimationDecoration { List<AnimationDecorationInstance> animationDecorations = []; AnimationDecoration(); factory AnimationDecoration.fromJson(Map<String, dynamic> json) => _$AnimationDecorationFromJson(json); Map<String, dynamic> toJson() => _$AnimationDecorationToJson(this); } @JsonSerializable(explicitToJson: true) class TextEffect with AnimationDecorationInstance { final AnimationDecorationType animation_decoration_type = AnimationDecorationType.text; @override get getArtifactDecorationType => animation_decoration_type; double fromMillis = 0, toMillis = 0; String text = ""; TextEffect(); factory TextEffect.fromJson(Map<String, dynamic> json) => _$TextEffectFromJson(json); Map<String, dynamic> toJson() => _$TextEffectToJson(this); } @JsonSerializable(explicitToJson: true) class FilterEffect with AnimationDecorationInstance { final AnimationDecorationType animation_decoration_type = AnimationDecorationType.filter; @override get getArtifactDecorationType => animation_decoration_type; int colorFilterAdaper = 0; FilterEffect(); factory FilterEffect.fromJson(Map<String, dynamic> json) => _$FilterEffectFromJson(json); Map<String, dynamic> toJson() => _$FilterEffectToJson(this); }
错误信息
2022-07-24 12:54:23 Could not generate `fromJson` code for `animationDecorations` because of type `AnimationDecorationInstance`. 2022-07-24 12:54:23 package:sdg4/dto/animation_decoration.dart:14:37 2022-07-24 12:54:23 ╷ 2022-07-24 12:54:23 14 │ List<AnimationDecorationInstance> animationDecorations = []; 2022-07-24 12:54:23 │ ^^^^^^^^^^^^^^^^^^^^ 2022-07-24 12:54:23 ╵
解决方案:自定义JsonConverter处理多态序列化
json_annotation无法自动处理抽象类的多态序列化,需要自定义JsonConverter来根据类型字段区分并转换子类实例。
步骤1:修正抽象类继承关系
抽象类应使用继承而非混入(with),调整子类的继承方式:
abstract class AnimationDecorationInstance { AnimationDecorationType get getArtifactDecorationType; Map<String, dynamic> toJson(); } class TextEffect extends AnimationDecorationInstance { ... } class FilterEffect extends AnimationDecorationInstance { ... }
步骤2:创建自定义转换类
实现JsonConverter,负责序列化/反序列化时的类型判断与转换:
class AnimationDecorationConverter implements JsonConverter<AnimationDecorationInstance, Map<String, dynamic>> { const AnimationDecorationConverter(); @override AnimationDecorationInstance fromJson(Map<String, dynamic> json) { final type = AnimationDecorationType.values.byName(json['animation_decoration_type']); switch (type) { case AnimationDecorationType.text: return TextEffect.fromJson(json); case AnimationDecorationType.filter: return FilterEffect.fromJson(json); default: throw Exception('Unknown animation decoration type: $type'); } } @override Map<String, dynamic> toJson(AnimationDecorationInstance object) { return object.toJson(); } }
步骤3:为列表字段绑定转换器
在AnimationDecoration类的animationDecorations字段上添加转换器注解:
@JsonSerializable(explicitToJson: true) class AnimationDecoration { @JsonKey(converter: AnimationDecorationConverter()) List<AnimationDecorationInstance> animationDecorations = []; AnimationDecoration(); factory AnimationDecoration.fromJson(Map<String, dynamic> json) => _$AnimationDecorationFromJson(json); Map<String, dynamic> toJson() => _$AnimationDecorationToJson(this); }
完整修改后代码
import 'package:json_annotation/json_annotation.dart'; part 'animation_decoration.g.dart'; @JsonEnum() enum AnimationDecorationType { text, filter } abstract class AnimationDecorationInstance { AnimationDecorationType get getArtifactDecorationType; Map<String, dynamic> toJson(); } class AnimationDecorationConverter implements JsonConverter<AnimationDecorationInstance, Map<String, dynamic>> { const AnimationDecorationConverter(); @override AnimationDecorationInstance fromJson(Map<String, dynamic> json) { final type = AnimationDecorationType.values.byName(json['animation_decoration_type']); switch (type) { case AnimationDecorationType.text: return TextEffect.fromJson(json); case AnimationDecorationType.filter: return FilterEffect.fromJson(json); default: throw Exception('Unknown animation decoration type: $type'); } } @override Map<String, dynamic> toJson(AnimationDecorationInstance object) { return object.toJson(); } } @JsonSerializable(explicitToJson: true) class AnimationDecoration { @JsonKey(converter: AnimationDecorationConverter()) List<AnimationDecorationInstance> animationDecorations = []; AnimationDecoration(); factory AnimationDecoration.fromJson(Map<String, dynamic> json) => _$AnimationDecorationFromJson(json); Map<String, dynamic> toJson() => _$AnimationDecorationToJson(this); } @JsonSerializable(explicitToJson: true) class TextEffect extends AnimationDecorationInstance { final AnimationDecorationType animation_decoration_type = AnimationDecorationType.text; @override AnimationDecorationType get getArtifactDecorationType => animation_decoration_type; double fromMillis = 0, toMillis = 0; String text = ""; TextEffect(); factory TextEffect.fromJson(Map<String, dynamic> json) => _$TextEffectFromJson(json); @override Map<String, dynamic> toJson() => _$TextEffectToJson(this); } @JsonSerializable(explicitToJson: true) class FilterEffect extends AnimationDecorationInstance { final AnimationDecorationType animation_decoration_type = AnimationDecorationType.filter; @override AnimationDecorationType get getArtifactDecorationType => animation_decoration_type; int colorFilterAdaper = 0; FilterEffect(); factory FilterEffect.fromJson(Map<String, dynamic> json) => _$FilterEffectFromJson(json); @override Map<String, dynamic> toJson() => _$FilterEffectToJson(this); }
重新生成序列化代码
执行命令重新生成代码:
flutter pub run build_runner build
内容的提问来源于stack exchange,提问作者Defarine
相关产品推荐
相关产品推荐

