嵌套DTO列表转JSON触发ArgumentError错误,求排查方案
问题:Firebase存储GroupDto时出现MemberDto实例无法序列化错误
我有一个包含Member列表属性的Group领域类,为将数据存入Firebase,实现了GroupDto与MemberDto类用于领域模型与JSON的双向转换。
近期保存群组更新时频繁触发错误:
ArgumentError (Invalid argument: Instance of 'MemberDto')

排查发现错误发生在GroupDto转JSON过程中,映射时直接存储MemberDto实例列表,而非转换后的JSON结构:
我已为MemberDto设置explicitToJson: true,但问题仍存在,请问成因是什么?
相关代码
GroupDto与MemberDto实现代码
@JsonSerializable(includeIfNull: false) class GroupDto { @JsonKey(includeFromJson: false, includeToJson: false) final String? id; final String title; final String? description; final List<MemberDto>? members; GroupDto({ this.id, required this.title, this.description, this.members, }); factory GroupDto.fromDomain(Group group) { return GroupDto( id: group.id, title: group.title.getOrCrash(), description: group.description, members: group.members.isNotEmpty ? group.members.map((e) => MemberDto.fromDomain(e)).toList() : null, ); } Group toDomain() { return Group( id: id, title: ItemTitle(title), description: description, members: members != null ? members!.map((dto) => dto.toDomain()).toList() : const [], ); } factory GroupDto.fromFirestore( Map<String, dynamic> json, String documentId) => _$GroupDtoFromJson(json).copyWith(id: documentId); factory GroupDto.fromJson(Map<String, dynamic> json) => _$GroupDtoFromJson(json); Map<String, dynamic> toJson() => _$GroupDtoToJson(this); GroupDto copyWith({ String? id, String? title, String? description, List<MemberDto>? members, }) { return GroupDto( id: id ?? this.id, title: title ?? this.title, description: description ?? this.description, members: members ?? this.members, ); } } @JsonSerializable(includeIfNull: false, explicitToJson: true) class MemberDto { final String userId; final MembershipStatus status; MemberDto({ required this.userId, required this.status, }); factory MemberDto.fromDomain(Member membership) { return MemberDto( userId: membership.userId, status: membership.status, ); } Member toDomain() { return Member( userId: userId, status: status, ); } factory MemberDto.fromJson(Map<String, dynamic> json) => _$MemberDtoFromJson(json); Map<String, dynamic> toJson() => _$MemberDtoToJson(this); }
自动生成的JsonSerializable代码
// GENERATED CODE - DO NOT MODIFY BY HAND part of 'group_dto.dart'; // ************************************************************************** // JsonSerializableGenerator // ************************************************************************** GroupDto _$GroupDtoFromJson(Map<String, dynamic> json) => GroupDto( title: json['title'] as String, description: json['description'] as String?, members: (json['members'] as List<dynamic>?) ?.map((e) => MemberDto.fromJson(e as Map<String, dynamic>)) .toList(), ); Map<String, dynamic> _$GroupDtoToJson(GroupDto instance) { final val = <String, dynamic>{ 'title': instance.title, }; void writeNotNull(String key, dynamic value) { if (value != null) { val[key] = value; } } writeNotNull('description', instance.description); writeNotNull('members', instance.members); return val; } MemberDto _$MemberDtoFromJson(Map<String, dynamic> json) => MemberDto( userId: json['userId'] as String, status: $enumDecode(_$MembershipStatusEnumMap, json['status']), ); Map<String, dynamic> _$MemberDtoToJson(MemberDto instance) => <String, dynamic>{ 'userId': instance.userId, 'status': _$MembershipStatusEnumMap[instance.status]!, }; const _$MembershipStatusEnumMap = { MembershipStatus.active: 'active', MembershipStatus.invited: 'invited', MembershipStatus.notYetSent: 'notYetSent', MembershipStatus.rejected: 'rejected', MembershipStatus.left: 'left', MembershipStatus.removed: 'removed', MembershipStatus.none: 'none', };
问题成因与解决方案
核心原因
从自动生成的_$GroupDtoToJson代码可以直接定位问题:
writeNotNull('members', instance.members);
这里直接将instance.members(List<MemberDto>类型)赋值给JSON字段,没有调用每个MemberDto实例的toJson()方法。
MemberDto上的explicitToJson: true配置仅作用于该类内部的嵌套对象,无法影响外部类(GroupDto)对它的序列化处理。
解决方案
给GroupDto的members字段添加@JsonKey(explicitToJson: true)注解,告知JsonSerializable需要递归序列化列表中的每个MemberDto:
修改GroupDto中的成员定义:
@JsonKey(explicitToJson: true) final List<MemberDto>? members;
重新运行代码生成命令:
flutter pub run build_runner build
此时自动生成的_$GroupDtoToJson代码会更新为:
writeNotNull('members', instance.members?.map((e) => e.toJson()).toList());
这样每个MemberDto都会被转换成对应的JSON对象后存入列表,即可解决序列化错误。
内容的提问来源于stack exchange,提问作者Charlie Page
相关产品推荐
相关产品推荐

