Предположим, у меня есть следующая модель (с использованием замороженного):
@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,
};
Как я могу это исправить? Есть ли лучший способ конвертировать карты в списки и наоборот, используя замороженный/json_serializable? Спасибо.
Кажется, проблема в том, чтобы 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()
.
Учитывая все это, возможно, было бы проще расширить класс User
вручную, добавив метод toJson
и конструктор фабрики fromJson
.
Вы все равно можете использовать freezed
для создания других удобных методов, например copyWith
и т. д.
Ну, он просто попробовал это без каких-либо общих аргументов, и это, похоже, работает. Это неудачно. Ну что ж :)
Поддерживаются ли дженерики? Я только что попытался удалить общий аргумент V и заменить его просто логическим значением, но он все равно не работает.