Reputation: 831
I have a class called Groups
that has a property that contains a list of Member
s.
To send this to Firebase, I have a GroupDto
and MemberDto
class that converts these values to and from the domain, and to and from JSON.
I noticed a recent issue where every time I try to save a group update, I'm getting this error that says:
ArgumentError (Invalid argument: Instance of 'MemberDto')
It seems to happen as part of the method that converts the GroupDto to Json, when I look at the value that's being mapped, it seems to be storing those as a list of MemberDto instead of a list of mapped values:
I have this list of MemberDtos set to also convert to Json, with explicitToJson equal to true.
Any idea what could be causing this?
Here are my classes for GroupDto and 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);
}
And here is the auto-generated JsonSerializable code:
// 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',
};
Upvotes: 1
Views: 710
Reputation: 1597
To get the list of mapped values from the instance try this example: Try getting the list of mapped values by mapping each instance to json then to list.
Example
An instance of GroupDto
GroupDto groups = GroupDto.fromDomain(
Group(
title: 'first group',
members: [
Member(userId: 'first user', status: MembershipStatus.active),
Member(userId: 'second user', status: MembershipStatus.active),
],
),
);
toJson()
on groups
, it should return a map Map<String, dynamic> groupsMap = groups.toJson();
MemberDto
from the map List<MemberDto> members = groupsMap['members'];
toJson()
method, then return them as list with toList()
List<Map<String, dynamic>> membersMapList = members
.map((e) => e.toJson())
.toList();
That should give you a map of MembersDto
Edit
The problem is with the nested List<MemberDto>?
object.
If you want the the package to do it for you, Change the explicitToJson
option of the JsonSerializable
annotation in the parent class to true
.
{bool? explicitToJson}
If true, generated toJson methods will explicitly call toJson on nested objects.
@JsonSerializable(includeIfNull: false, explicitToJson: true)
class GroupDto {
...
Thanks to this answer for pointing it out.
Upvotes: 2