json_serializable.dart
json_serializable.dart copied to clipboard
Please explain generic types deserialization
Generated code:
Response<T> _$ResponseFromJson<T>(
Map<String, dynamic> json,
T Function(Object json) fromJsonT,
) {
return Response<T>()
..status = json['status'] as int
..value = fromJsonT(json['value']);
}
Seems like it is not fully automated for any types. It claims to provide Function for concrete types parsing. My try:
@JsonSerializable(createToJson: false, genericArgumentFactories: true)
class Response<T> {
final T data;
final Status status;
Response({this.data, this.status});
factory Response.fromJson(Map<String, dynamic> json) => _$ResponseFromJson(json, (jsonObject) {
switch (jsonObject) {
case User:
return User.fromJson(jsonObject) as T;
case Profile:
return Profile.fromJson(jsonObject) as T;
case StartChangeClientPhoneResponseBody:
return StartChangeClientPhoneResponseBody.fromJson(jsonObject) as T;
// primitive types, bool, etc.
default:
return jsonObject;
}
});
}
It throws runtime exception:
Dart Unhandled Exception: type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'Profile'
Documentation says nothing on how to handle it properly.
I don't think you can switch
over instances + types.
Maybe this example will help you? https://github.com/google/json_serializable.dart/blob/master/example/lib/tuple_example.dart
Maybe this example will help you? https://github.com/google/json_serializable.dart/blob/master/example/lib/tuple_example.dart
Thanks, this signature is correct: factory Response.fromJson(Map<String, dynamic> json, T Function(Object json) fromJsonT) => _$ResponseFromJson(json, fromJsonT);
The problem is that Retrofit doesn't generate fromJsonT
of correct type. It generates final value = Response<User>.fromJson(_result.data);
, omitting the 2nd parameter.
What's Retrofit
?
It is an extension for Dio HTTP client: https://pub.dev/packages/retrofit It is a popular API generator, which we use.
Okay, it is a problem on Retrofit side, and they are aware of it and probably fix it in a next release. Currently I can manually make requests like
final _result = await dio.get('$baseUrl/currentUser');
return Response<User>.fromJson(_result.data, (data) => User.fromJson(data));
It's worth mentioning in docs that factory for generic types is factory Response.fromJson(Map<String, dynamic> json, T Function(Object json) fromJsonT) => _$ResponseFromJson(json, fromJsonT);
because now it is not, and it made me lost: