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

嵌套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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 15:40:54