假设我有以下模型(使用freezed):
@freezed
class User with _$User {
const factory User({
required UserID id,
required List<String> categories,
}) = _User;
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
}
我想从如下所示的 JSON 对象反序列化此模型:
{
"id": "1234",
"categories": {
"A": true,
"B": true
}
}
显然默认的序列化不起作用,所以我尝试实现自定义的
JsonConverter
:
class ListMapConverter<K, V> implements JsonConverter<List<K>, Map<K, V>> {
const ListMapConverter(this._value);
final V _value;
@override
List<K> fromJson(Map<K, V> json) => json.keys.toList();
@override
Map<K, V> toJson(List<K> object) => {for (final e in object) e: _value};
}
我像这样注释了模型的属性:
@ListMapConverter<String, bool>(true) required List<String> categories
这不起作用,并且生成的输出中不使用自定义转换器:
_$UserImpl _$$UserImplFromJson(Map<String, dynamic> json) => _$UserImpl(
id: UserID.fromJson(json['id'] as String),
categories: (json['categories'] as List<dynamic>)
.map((e) => e as String)
.toList(),
);
Map<String, dynamic> _$$UserImplToJson(_$UserImpl instance) =>
<String, dynamic>{
'id': instance.id,
'categories': instance.categories,
};
我该如何解决这个问题?是否有更好的方法使用 freezed/json_serialized 将映射转换为列表,反之亦然?谢谢。
问题似乎是
json_serializable
默默地忽略你的通用转换器。最重要的是,json_serializable
不支持带有构造函数参数的转换器,请参阅此问题。
解决方法是使转换器成为非泛型并使用命名构造函数来提供实例变量
_value
:
class ListMapConverter implements JsonConverter<List<String>, Map<String, bool>> {
// const ListMapConverter(this._value);
const ListMapConverter.zero() : _value = false;
const ListMapConverter.one() : _value = true;
final bool _value;
@override
List<String> fromJson(Map<String, bool> json) => json.keys.toList();
@override
Map<String, bool> toJson(List<String> object) => {for (final e in object) e: _value};
}
然后您可以使用注释:
@ListMapConverter.one()
。
鉴于这一切,手动添加方法
toJson
和工厂构造函数 fromJson
可能会更容易。您仍然可以使用 freezed
生成其他便捷方法,例如 copyWith
等。