You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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。现提出以下疑问:

  1. 为何fromJson不能使用原名,而toJson可以?
  2. 这种实现方式是否正确?
  3. 能否不依赖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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 09:35:31