Reputation: 1715
I'm using the freezed package to work with immutable models and make use of the built-in feature for json serialization by the json_serializable package. I have a simple User
class/model with different union types (UserLoggedIn
, UserGeneral
, UserError
):
@freezed
class User with _$User {
const factory User(String id, String email, String displayName) =
UserLoggedIn;
const factory User.general(String email, String displayName) = UserGeneral;
const factory User.error(String message) = UserError;
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
}
Since I'm using multiple constructors and don't want my API to include the runtimeType
key as suggested by the documentation, I can write a converter (scroll a bit more down, sentence starts with: If you don't control the JSON response, then you can implement a custom converter.).
So based on that I wrote the following converter class:
class UserConverter implements JsonConverter<User, Map<String, dynamic>> {
const UserConverter();
@override
User fromJson(Map<String, dynamic> json) {
if (json['id'] != null) {
return UserLoggedIn.fromJson(json);
} else if (json['error'] != null) {
return UserError.fromJson(json);
} else {
return UserGeneral.fromJson(json);
}
}
@override
Map<String, dynamic> toJson(User data) => data.toJson();
}
The documentation now references another class (a wrapper class) which would now use this converter via annotation, something like this:
@freezed
class UserModel with _$UserModel {
const factory UserModel(@UserConverter() User user) = UserModelData;
factory UserModel.fromJson(Map<String, dynamic> json) =>
_$UserModelFromJson(json);
}
Question: is it possible to make use of this converter without having to use a wrapper class (UserModel
)?
Reasoning: this wrapper class is adding another layer of abstraction which is not needed (in my cases). Especially since the wrapper class does not have any other benefit / purpose and it feels like it should be possible to do that without using it.
Upvotes: 4
Views: 2747
Reputation: 2087
This might sound obvious and lazy, but assuming the following suffice, why don't you write your custom fromJson
in your model class?
// We write a custom fromjson but still want fromjson constructors
// to be generated
@Freezed(fromJson: true, toJson: true)
sealed class User with _$User {
const factory User(String id, String email, String displayName) =
UserLoggedIn;
const factory User.general(String email, String displayName) = UserGeneral;
const factory User.error(String message) = UserError;
factory User.fromJson(Map<String, dynamic> json) {
// We paste our JsonConverter.fromJson in a fromjson factory
if (json['id'] != null) {
return UserLoggedIn.fromJson(json);
} else if (json['error'] != null) {
return UserError.fromJson(json);
} else {
return UserGeneral.fromJson(json);
}
}
}
With this, you still obtain a toJson
method, which is subject to other @freezed
rules you've mentioned.
Upvotes: 7