I'm trying to create a custom JsonConverter for a specific field on my class. The reason for this is that the API I am retrieving data from has a meta
key that either returns a dictionary or an empty array, but should always be saved as Map<String, dynamic>
.
My code:
import 'package:json_annotation/json_annotation.dart';
part 'tag.g.dart';
@JsonSerializable()
class Tag {
int? id;
int? count;
String? description;
Uri? link;
String? name;
String? slug;
String? taxonomy;
@EmptyMetaToMapConverter()
Map<String, dynamic>? meta;
Tag();
factory Tag.fromJson(Map<String, dynamic> json) => _$TagFromJson(json);
Map<String, dynamic> toJson() => _$TagToJson(this);
}
class EmptyMetaToMapConverter extends JsonConverter<Map, Object?> {
const EmptyMetaToMapConverter();
@override
Map<String, dynamic> fromJson(Object? json) {
if (json is List) return {};
if (json is Map<String, dynamic>) return json;
throw Exception();
}
@override
Map toJson(Map object) => object;
}
When I run flutter pub run build_runner build
, the corresponding tag.g.dart
file is as follows:
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'tag.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
Tag _$TagFromJson(Map<String, dynamic> json) => Tag()
..id = json['id'] as int?
..count = json['count'] as int?
..description = json['description'] as String?
..link = json['link'] == null ? null : Uri.parse(json['link'] as String)
..name = json['name'] as String?
..slug = json['slug'] as String?
..taxonomy = json['taxonomy'] as String?
..meta = json['meta'] as Map<String, dynamic>?; // The custom converter seems to have no effect here
Map<String, dynamic> _$TagToJson(Tag instance) => <String, dynamic>{
'id': instance.id,
'count': instance.count,
'description': instance.description,
'link': instance.link?.toString(),
'name': instance.name,
'slug': instance.slug,
'taxonomy': instance.taxonomy,
'meta': instance.meta,
};
When I try to deserialize a JSON object with a meta
field containing an empty list, it raises an error. What am I doing wrong?
Flutter version: 3.16.8
json_serializable: ^6.7.1
build_runner: ^2.4.8
json_annotation: ^4.8.1
Your custom converter isn't being used because it's using the wrong type of Map
. Map
implicitly means Map<dynamic, dynamic>
, while the map that you need is Map<String, dynamic>
. There are 3 places where you need to change it:
class EmptyMetaToMapConverter extends JsonConverter<Map<String, dynamic>, Object?> { // (1)
const EmptyMetaToMapConverter();
@override
Map<String, dynamic> fromJson(Object? json) {
if (json is List) return {};
if (json is Map<String, dynamic>) return json;
throw Exception();
}
@override
Map<String, dynamic> toJson(Map<String, dynamic> object) => object; // (2) and (3)
}