i think this his highly related to this issue
but i have some trouble using it for my needs. I either use it wrong or it is currently not possible.
this is an example of what i want to parse
{
"status": "success",
"message": null,
"code": 0,
"data": {
"timestamp": 0,
"result": [
{
"id": 409,
"active": true,
"accessToken": "12345_abc",
}
]
}
}
and here the corresponding classes
@JsonSerializable()
class WsResponse<T> extends Object with _$WsResponseSerializerMixin<T> {
String status;
String message;
int code;
@JsonKey(fromJson: _dataFromJson, toJson: _dataToJson)
WsData<T> data;
WsResponse({this.status, this.message, this.code, this.data});
factory WsResponse.fromJson(Map<String, dynamic> json) => _$WsResponseFromJson<T>(json);
}
here i have an outer "class" with status message and code that works like every ordinary class.
@JsonSerializable()
class WsData<T> extends Object with _$WsDataSerializerMixin<T> {
int timestamp;
@JsonKey(fromJson: _resultFromJson, toJson: _resultToJson)
List<T> result;
WsData({this.timestamp, this.result});
factory WsData.fromJson(Map<String, dynamic> json) => _$WsDataFromJson<T>(json);
}
@JsonSerializable()
class WsLogin extends Object with _$WsLoginSerializerMixin {
int id;
bool active;
String accessToken;
WsLogin({this.id, this.active, this.accessToken,});
factory WsLogin.fromJson(Map<String, dynamic> json) => _$WsLoginFromJson(json);
}
I omitted the fromJson etc. definitions because i don't know how to express them right either (may be the part where i am wrong)
but if i try _dataFromJson for example
WsData<T> _dataFromJson<T>(Map<String, dynamic> input) {
return input['data'] as WsData<T>;
}
i get an error with
[SEVERE] json_serializable on lib/webservice/webservice.dart:
Error running JsonSerializableGenerator
Error with `@JsonKey` on `data`. The `fromJson` function `_dataFromJson` return type `WsData<T>` is not compatible with field type `WsData<T>`.
package:crewlove/webservice/webservice.dart:31:13
WsData<T> data;
^^^^
which is surprising for me at first. Omitting the @JsonKey annotations does not help either as i think its necessary for generics. But i don't know how to express my intent here.
My intent is to use it like this
var wsLoginResp = new WsResponse<WsLogin>.fromJson(json.decode(resp));
Update this code:
WsData<T> _dataFromJson<T>(Map<String, dynamic> input) {
return input['data'] as WsData<T>;
}
to
T _dataFromJson<T>(Map<String, dynamic> input) {
return input['data'] as T;
}
(Although you'll need to put in some sort of helper here – since the input JSON is not WsData<T> or whatever....
Closing this to get it off my queue. Please reopen if you still have issues...
I'm trying to achieve something similar to create a generic object that can be used for endpoints that return a collection/page of objects.
{
"page": 1,
"results": [
.... objects ....
],
"total_results": 14,
"total_pages": 1
}
@JsonSerializable()
class ResponseCollection<T> extends Object
with _$ResponseCollectionSerializerMixin<T> {
@JsonKey(name: "page")
final int page;
@JsonKey(name: "total_results")
final int totalResults;
@JsonKey(name: "total_pages")
final int totalPages;
@JsonKey(fromJson: resultFromJson, toJson: _resultToJson)
final List<T> results;
ResponseCollection(
this.page, this.totalResults, this.totalPages, this.results);
factory ResponseCollection.fromJson(Map<String, dynamic> json) =>
_$ResponseCollectionFromJson<T>(json);
}
List<T> resultFromJson<T>(List input) {
// looking for a way to check what T is we can call the correct Class.formJson()
return input.map((f) {
if (T is MovieSearchResult) {
return MovieSearchResult.fromJson(f);
} else if (T is Movie) {
return Movie.fromJson(f);
} else {
throw Exception("Unknow type");
}
});
}
Map<String, dynamic> _resultToJson<T>(List<T> input) => {'results': input};
@aegis123 – does that work for you? You'd need to be running the VM w/ --preview-dart-2 so that the generic parameter to resultFromJson shows up...
Thats should be enable by default in beta 3 right? Or do I have to add --preview-dart-2 to flutter packages pub run build_runner build make it use the dart 2 preview?
You need a version of Flutter where build_runner is running w/ --preview-dart-2. That should be coming soon...
Is that in preview 1 available?
I don't think so...
@kevmoo or @aegis123 : Do you have any working example where the class has a List of generics?
I can't achieve that @aegis123 wants (generic object that can be used for endpoints that return a collection/page of objects).
I checked the examples and the tests of json_serializable, but I can't figure out how to use it with List of generics.
Let me hack on this now...
I'm working on a fix for this now...
Closing this out for https://github.com/dart-lang/json_serializable/issues/308 – trying to brainstorm a solution. Please comment!
CC @pythoneer @mecseid @aegis123 – I think the solution in https://github.com/dart-lang/json_serializable/pull/312 is pretty flexible.
Take a look!
pls see my comment on the pull request
@aegis123 – once we publish, I'll update the example package w/ usage...examples...
@kevmoo do you have an example on how to use this?
@aegis123 – please sketch out the the classes you want to write and I'll create an example of how to serialize – hopefully. 😄
@JsonSerializable()
class GenericCollection<T> {
@JsonKey(name: 'page')
final int page;
@JsonKey(name: 'total_results')
final int totalResults;
@JsonKey(name: 'total_pages')
final int totalPages;
@JsonKey(name: 'results')
final List<T> results;
GenericCollection(
{this.page, this.totalResults, this.totalPages, this.results});
factory GenericCollection.fromJson(Map<String, dynamic> json) =>
_$GenericCollectionFromJson<T>(json);
}
and it should be able to be called like final reviewCollection = GenericCollection<Review>.fromJson(someJson) or if you call another endpoint GenericCollection<Movie>.fromJson(someJson). Then there should probably be an @GenericConverter() on the GenericCollection<T> class if I have read the code correctly which contains the implementation on checking the class/instance type of T and calling the correct factory for the type like Movie.fromJson(json) or Review.fromJson(json).
@kevmoo If your quick I might be able to add to a talk/coding demo I'm giving at Mobilization tomorrow 😉
@aegis123 – https://github.com/dart-lang/json_serializable/pull/350/commits/ee2c5c788279af01860624303abe16811850b82c
Just for you
Thx 😄.
For Flutter there is no way to do something like
class CustomType {}
void convert<T>(Object obj) {
if( obj instanceOf CustomType) {
return CustomType();
}
}
I'm trying to achieve something similar to create a generic object that can be used for endpoints that return a collection/page of objects.
{ "page": 1, "results": [ .... objects .... ], "total_results": 14, "total_pages": 1 }@JsonSerializable() class ResponseCollection<T> extends Object with _$ResponseCollectionSerializerMixin<T> { @JsonKey(name: "page") final int page; @JsonKey(name: "total_results") final int totalResults; @JsonKey(name: "total_pages") final int totalPages; @JsonKey(fromJson: resultFromJson, toJson: _resultToJson) final List<T> results; ResponseCollection( this.page, this.totalResults, this.totalPages, this.results); factory ResponseCollection.fromJson(Map<String, dynamic> json) => _$ResponseCollectionFromJson<T>(json); } List<T> resultFromJson<T>(List input) { // looking for a way to check what T is we can call the correct Class.formJson() return input.map((f) { if (T is MovieSearchResult) { return MovieSearchResult.fromJson(f); } else if (T is Movie) { return Movie.fromJson(f); } else { throw Exception("Unknow type"); } }); } Map<String, dynamic> _resultToJson<T>(List<T> input) => {'results': input};
maybe you can do complexly like this ?
List<T> resultFromJson<T>(List input) {
// looking for a way to check what T is we can call the correct Class.formJson()
String _class = T.toString();
return input.map((f) {
if (_class == 'MovieSearchResult') {
return MovieSearchResult.fromJson(f);
} else if (_class == 'Movie') {
return Movie.fromJson(f);
} else {
throw Exception("Unknow type");
}
});
}
When I call the api like
final HttpResponseDataListModel<SubjectBasicModel> result =
await Http.get<HttpResponseDataListModel<SubjectBasicModel>>(url, params: params);
I will get this error:
_CastError(type 'HttpResponseDataListModel<dynamic>' is not a subtype of type 'HttpResponseDataListModel<SubjectBasicModel>' in type cast)
seems it can't take use of the nested generic. Should I just don't use the nested generic while calling apis or manually test the types of the nested data?
is there a better way to do this?
Does anyone have an example of generics working? Honestly I have no idea how they possibly could work unless we had some kind of abstract class called JsonSerializableOutput or something like that
@JsonSerializable(fieldRename: FieldRename.snake)
class TwicApiResponse<T> {
TwicApiResponse(this.data, this.errors);
final T data;
final List<_Error> errors;
factory TwicApiResponse.fromJson(Map<String, dynamic> json) =>
_$TwicApiResponseFromJson(json);
}
[SEVERE] json_serializable:json_serializable on lib/services/twic_rest_service/models/models.dart:
Error running JsonSerializableGenerator
Could not generate `fromJson` code for `data`.
None of the provided `TypeHelper` instances support the defined type.
package:twic/services/twic_rest_service/models/response.dart:20:11
â•·
20 │ final T data;
│ ^^^^
╵
I'm just going to say my data type is Map
I'm just going to say my data type is Map
and unwrap it one more time when I do my fetching operations.
That's a completely fine solution
Thanks for the help, Kevin!
not quite the cleanest way.. that violates the concept of generic
. any data class with serialization should be acceptable – uzu Mar 4 at 6:59
Take a look at https://github.com/dart-lang/json_serializable/blob/master/example/lib/json_converter_example.dart
this example seems to be the cleanest (?) way yet, but violates the concepts of generic
Take a look at https://github.com/dart-lang/json_serializable/blob/master/example/lib/json_converter_example.dart
also, with this solution it cannot deal with data strucuture of List<T>.
List<T> it self is another generic type, lets say, A.
A.containsKey("key")?? its just non sense
Most helpful comment
maybe you can do
complexlylike this ?