Flutter中使用Freezed实现对象转JSON的相关疑问
问题背景
我编写了一个Freezed数据类:
@freezed class GithubRepoDTO with _$GithubRepoDTO { const GithubRepoDTO._(); const factory GithubRepoDTO({ required UserDTO owner, required String name, @JsonKey(fromJson: _fromJson) required String description, @JsonKey(name: 'stargazers_count') required int stargazersCount, }) = _GithubRepoDTO; factory GithubRepoDTO.fromJson(Map<String, dynamic> json) = _$GithubRepoDTOFromJson(json); }
通过Freezed可以实现fromJson方法,但无法直接编写toJson方法。于是我引入了json_serializable,更新后的代码如下:
@freezed @JsonSerializable() class GithubRepoDTO with _$GithubRepoDTO { const GithubRepoDTO._(); const factory GithubRepoDTO({ required UserDTO owner, required String name, @JsonKey(fromJson: _fromJson) required String description, @JsonKey(name: 'stargazers_count') required int stargazersCount, }) = _GithubRepoDTO; factory GithubRepoDTO.toGithubRepoDTO(Map<String, dynamic> json) = _$GithubRepoDTOFromJson(json); Map<String, dynamic> toJson() => _$GithubRepoDTOToJson(this); }
现在我可以使用toJson方法,但出现新问题:fromJson无法使用原名,否则自动生成的代码会出现重复引用,因此我将其改名为toGithubRepoDTO。现提出以下疑问:
- 为何
fromJson不能使用原名,而toJson可以? - 这种实现方式是否正确?
- 能否不依赖json_serializable实现对象转JSON?
问题解答
1. 为什么fromJson不能用原名,toJson可以?
Freezed本身会自动生成一个fromJson工厂方法(当它处理JSON序列化逻辑时),而添加@JsonSerializable()注解后,json_serializable也会尝试生成同名的fromJson方法,这就导致了方法重复定义的冲突。
而toJson的情况不同:Freezed默认不会自动生成toJson方法(除非配置特定参数),json_serializable生成的_$GithubRepoDTOToJson是一个顶层函数,你手动编写的toJson实例方法只是调用这个生成函数,不会和自动生成的内容产生冲突,因此可以正常使用原名。
2. 这种实现方式是否正确?
这种写法能运行,但不是最优解。更规范的做法是让Freezed和json_serializable协作生成序列化方法,不需要手动修改fromJson的名称:
@freezed class GithubRepoDTO with _$GithubRepoDTO { const GithubRepoDTO._(); const factory GithubRepoDTO({ required UserDTO owner, required String name, @JsonKey(fromJson: _fromJson) required String description, @JsonKey(name: 'stargazers_count') required int stargazersCount, }) = _GithubRepoDTO; // 由Freezed调用json_serializable生成正确的序列化方法 factory GithubRepoDTO.fromJson(Map<String, dynamic> json) => _$GithubRepoDTOFromJson(json); Map<String, dynamic> toJson() => _$GithubRepoDTOToJson(this); }
同时需要在项目的build.yaml中添加配置,让Freezed启用json序列化支持:
targets: $default: builders: freezed: options: json: true
配置完成后重新运行代码生成命令,就不会出现方法重复的问题,也不用修改fromJson的名称。
3. 能否不依赖json_serializable实现对象转JSON?
可以,有两种常用方式:
- 手动实现
toJson:利用Freezed的私有构造函数,自行编写字段到JSON的映射逻辑:
这种方式适合结构简单的类,但字段较多时容易出错,且需要手动维护字段映射关系。@freezed class GithubRepoDTO with _$GithubRepoDTO { const GithubRepoDTO._(); const factory GithubRepoDTO({ required UserDTO owner, required String name, required String description, required int stargazersCount, }) = _GithubRepoDTO; factory GithubRepoDTO.fromJson(Map<String, dynamic> json) = _$GithubRepoDTOFromJson(json); Map<String, dynamic> toJson() { return { 'owner': owner.toJson(), 'name': name, 'description': description, 'stargazers_count': stargazersCount, }; } } - 启用Freezed内置JSON支持:在
build.yaml中配置json: true后,Freezed会自动生成toJson方法,无需显式依赖json_serializable(底层仍会复用其逻辑,但无需手动添加注解),运行代码生成命令后即可直接使用自动生成的toJson。
内容的提问来源于stack exchange,提问作者Akhil
相关产品推荐
相关产品推荐

