Open woprandi opened 7 months ago
Note: retrofit has no way of knowing what to call feomJson on, so it would need to implement something like genericArgumentFactories where we pass in the fromJson to the method
There's no reflection for lutter. So, you must tell retrofit the exact type before it generates code for you. Refer ApiResult<t>
for an example. @woprandi @ekuleshov
@trevorwang appreciate response. I'm aware of the issue involved with both generics and absence of reflection.
However it is a valid case to have rest api to receive or return a generic argument, when the type is not known at the compilation time. For such types the JsonSerializable
can generate special to/fromJson() methods that are taking additional parameters (i.e. genericArgumentFactories
option).
Currently retrofit generator is generating an invalid code like T.fromJson(_result.data!)
for such classes and it doesn't seem like it allows to pass generic arg factories as code generated by the JsonSerializable
is expecting.
It would be really helpful and would allow to deal with the issue without writing a bunch of boilerplate code, if we could specify additional parameters for the retrofit endpoint method, so the consuming code could provide appropriate generic factories and these factories would be wired with the to/fromJson calls generated by retrofit generator.
For example, a rest endpoint declaration could look like this:
@POST('/api/config/save')
@Headers({'Content-Type': 'application/json'})
Future<Config<T>> saveConfig<T>(
Config<T> config,
Object? Function(T value) toJson,
T Function(Object? json) fromJson);
Note that Config<T>
class is declared like that and defined the same generic arg factories params in to/fromJson methods.
@JsonSerializable(genericArgumentFactories: true)
class Config<T> {
...
T details;
factory Config.fromJson(Map<String, dynamic> json, T Function(Object? json) fromJsonT)
=> _$ReportConfigFromJson(json, fromJsonT);
Map<String, dynamic> toJson(Object? Function(T value) toJsonT) => _$ReportConfigToJson(this, toJsonT);
}
Is there any work around for this issue?
Is the following code now supported?
@immutable
@Freezed(genericArgumentFactories: true)
class EnumInfo<T> with _$EnumInfo<T> {
/// constructor
const factory EnumInfo({
///
T? code,
///
String? chineseValue,
///
String? englishValue,
}) = _EnumInfo;
/// Deserializes the given json into a [EnumInfo].
factory EnumInfo.fromJson(Map<String, dynamic> json, T Function(Object?) toJsonT) =>
_$EnumInfoFromJson(json, toJsonT);
}
@RestApi()
abstract class CommonApi {
@GET("your url")
Future<List<EnumInfo<int>>?> getTerms();
}
As specified here https://github.com/trevorwang/retrofit.dart/issues/627#issuecomment-1843458890
Generate invalid code :
final value = T.fromJson(_result.data!);
We also lost info if generic type is restricted
become
but it should be
Tested with 8.0.1 and 8.0.5