I have freezed model (simplified):
part 'initial_data_model.freezed.dart';
part 'initial_data_model.g.dart';
@freezed
class InitialDataModel with _$InitialDataModel {
const factory InitialDataModel() = Data;
const factory InitialDataModel.loading() = Loading;
const factory InitialDataModel.error([String? message]) = Error;
factory InitialDataModel.fromJson(Map<String, dynamic> json) => _$InitialDataModelFromJson(json);
}
documentation says how to assign custom converters on fields but not on model itself
I got json from backend and somewhere in api_provider I do
return InitialDataModel.fromJson(json);
I have no control on json structure, there aren't "runtimeType" and other stupid redundant things
when I want to create a model from json I call fromJson
I'm having this
flutter: CheckedFromJsonException
Could not create `InitialDataModel`.
There is a problem with "runtimeType".
Invalid union type "null"!
ok, again
I have api_provider
final apiProvider = Provider<_ApiProvider>((ref) => _ApiProvider(ref.read));
class _ApiProvider {
final Reader read;
_ApiProvider(this.read);
Future<InitialDataModel> fetchInitialData() async {
final result = await read(repositoryProvider).send('/initial_data');
return result.when(
(json) => InitialDataModel.fromJson(json),
error: (e) => InitialDataModel.error(e),
);
}
}
you may see I'm trying to create InitialDataModel
from json
this line throws an error I mentioned above
I don't understand how to create InitialDataModel from json, now in my example it's just empty model, there are no fields
(json) => InitialDataModel.fromJson(json),
json
here is Map, it shows an error even if I pass simple empty map {}
instead of real json object
The easiest solution is to use the correct constructor instead of _$InitialDataModelFromJson. Example:
@freezed
class InitialDataModel with _$InitialDataModel {
const factory InitialDataModel() = Data;
...
factory InitialDataModel.fromJson(Map<String, dynamic> json) => Data.fromJson(json);
}
The drawback of course is that you can only use the fromJson when you're sure you have the correct json, which isn't great. I actually wouldn't recommend this way because it leaves to the caller the burden of checking the validity and calling the correct constructor.
Another solution, maybe the best, is to follow the documentation and create a custom converter, even though this would require you to have two separated classes.
Otherwise you could chose a different approach and separate the data class from the union, so you'll have a union used just for the state of the request and a data class for the success response:
@freezed
class InitialDataModel with _$InitialDataModel {
factory InitialDataModel(/* here go your attributes */) = Data;
factory InitialDataModel.fromJson(Map<String, dynamic> json) => _$InitialDataModelFromJson(json);
}
@freezed
class Status with _$Status {
const factory Status.success(InitialDataModel model) = Data;
const factory Status.loading() = Loading;
const factory Status.error([String? message]) = Error;
}
and then
[...]
return result.when(
(json) => Status.success(InitialDataModel.fromJson(json)),
error: (e) => Status.error(e),
);
[...]