json_serializable.dart
json_serializable.dart copied to clipboard
Allow extension type as Map keys if it extends one of primitive json types or has toJson() method
Codegenerator logs error:
Could not generate
fromJson
code formap
because of typeItemId
. Map keys must be one of: Object, dynamic, enum, String, BigInt, DateTime, int, Uri.
@JsonSerializable(explicitToJson: true)
class Item {
Item({required this.id, required this.map});
final ItemId id;
// Problem here
final Map<ItemId, ItemId> map;
factory Item.fromJson(Map<String, dynamic> json) => _$ItemFromJson(json);
Map<String, dynamic> toJson() => _$ItemToJson(this);
}
extension type const ItemId(String id) {
factory ItemId.fromJson(String id) {
// Here could be some logic to parse the id
return ItemId(id);
}
String toJson() {
// Here could be some logic to convert the id to a string
return id;
}
}
Expected generated code
Item _$ItemFromJson(Map<String, dynamic> json) => Item(
id: ItemId.fromJson(json['id'] as String),
map: (json['map'] as Map<String, dynamic>).map(
(k, e) => MapEntry(ItemId.fromJson(k as String), ItemId.fromJson(e as String)),
),
);
Map<String, dynamic> _$ItemToJson(Item instance) => <String, dynamic>{
'id': instance.id.toJson(),
'map': instance.map.map((k, e) => MapEntry(k.toJson(), e.toJson())),
};
Also, the case with explicitToJson: false
could be tricky because in the ItemId
class, toJson
is just an extension method, and jsonEncode
will simply unbox the String id
value. This behavior is unexpected if the extension type has a toJson
method.