I have a generic data model in Flutter using the JsonSerializable. I want to pass a custom parameter name (e.g., "statistics") instead of a fixed name in the fromJson and toJson methods. Here's my current implementation:
import 'package:json_annotation/json_annotation.dart';
part 'data_model.g.dart';
@JsonSerializable(genericArgumentFactories: true)
class DataModel<T, P> {
final int? total;
final List<T> items;
final P? param;
DataModel({
this.total,
required this.items,
this.param,
});
factory DataModel.fromJson(
Map<String, dynamic> json,
T Function(Object?) fromJsonT,
P Function(Object?) fromJsonP,
) {
final List<dynamic> itemsJson = json['items'] as List<dynamic>;
final List<T> items = itemsJson
.map<T>((item) => fromJsonT(item as Map<String, dynamic>))
.toList();
final dynamic paramJson = json['statistics'] as dynamic; // <- pass the param name instead of 'statistics'
final P? pamPam = fromJsonP(paramJson);
return DataModel<T, P>(
total: (json['total'] != null && json['total'] is int)
? json['total'] as int
: null,
param: pamPam,
items: items,
);
}
Map<String, dynamic> toJson(Object? Function(T) toJsonT, Object? Function(P) toJsonP) {
final List<dynamic> itemsJson =
items.map<dynamic>((item) => toJsonT(item)).toList();
return {
'total': total,
'statistics': toJsonP, // <- pass the param name instead of 'statistics'
'items': itemsJson,
};
}
}
Here is JSON example how it works now:
{
"total":2,
"items":[
{
"id":1,
"name":"John"
},
{
"id":2,
"name":"Max"
}
],
"statistics":{
"views":50,
"downloads":100
}
}
My objective is to make field statistics more generic. The aim is to establish a logic wherein an alternative object can be passed as a generic parameter alongside the respective JSON key name. For instance, "other" could be passed instead of "statistics." Example:
{
"total":2,
"items":[
{
"id":1,
"name":"John"
},
{
"id":2,
"name":"Max"
}
],
"other":{
"invites":50
}
}
Maybe we can create one more parameter like 'N' name and parse it in fromJson and toJson methods. Or maybe it is not possible at all.
You can turn the field name in a parameter/property, and keep 'statistics'
as a default.
import 'package:json_annotation/json_annotation.dart';
part 'data_model.g.dart';
@JsonSerializable(genericArgumentFactories: true)
class DataModel<T, P> {
final int? total;
final List<T> items;
final P? param;
final String paramName;
DataModel({
this.total,
required this.items,
this.param,
required this.paramName,
});
factory DataModel.fromJson(
Map<String, dynamic> json,
T Function(Object?) fromJsonT,
P Function(Object?) fromJsonP,
{String paramName = 'statistics'}
) {
final List<dynamic> itemsJson = json['items'] as List<dynamic>;
final List<T> items = itemsJson
.map<T>((item) => fromJsonT(item as Map<String, dynamic>))
.toList();
final dynamic paramJson = json[paramName] as dynamic;
final P? pamPam = fromJsonP(paramJson);
return DataModel<T, P>(
total: (json['total'] != null && json['total'] is int)
? json['total'] as int
: null,
param: pamPam,
items: items,
paramName: paramName,
);
}
Map<String, dynamic> toJson(Object? Function(T) toJsonT, Object? Function(P) toJsonP) {
final List<dynamic> itemsJson =
items.map<dynamic>((item) => toJsonT(item)).toList();
return {
'total': total,
paramName: toJsonP,
'items': itemsJson,
};
}
}
(By the way, JsonSerializable
is not really used here, you are just parsing and formatting it without using its generated code. Are you sure you need it?)