【问题标题】:Flutter JSON Serialization - Not generating *.g.dart filesFlutter JSON 序列化 - 不生成 *.g.dart 文件
【发布时间】:2020-02-10 02:47:10
【问题描述】:

我是 Flutter 的新手,目标是序列化包含其他较小对象的复杂 JSON 对象。

使用json_serializable: ^2.0.0pubspec.yaml 文件看起来像这样。

dependencies:
  intl: ^0.15.7
  json_annotation: ^2.0.0
  built_value: ^6.7.1
  flutter:
    sdk: flutter

dev_dependencies:
  build_runner: ^1.0.0
  json_serializable: ^2.0.0
  built_value_generator: ^6.7.1
  flutter_test:
    sdk: flutter

user.dart 看起来像这样

import 'package:json_annotation/json_annotation.dart';

part 'user.g.dart';

@JsonSerializable(nullable: false)
class User {
  final String firstName;
  final String lastName;
  final DateTime dateOfBirth;
  User({this.firstName, this.lastName, this.dateOfBirth});
  factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
  Map<String, dynamic> toJson() => _$UserToJson(this);
}

我已经尝试过flutter pub run build_runner build,但文件 user.g.dart 没有被创建,我遇到了这个问题。

我还添加了build.yaml 文件,代码如下

targets:
  $default:
    builders:
      built_value_generator|built_value:
        generate_for:
          - model/*.dart
      json_serializable|json_serializable:
        generate_for:
          - model/*.dart

谁能让我知道我在这里缺少什么。谢谢

【问题讨论】:

    标签: json flutter


    【解决方案1】:

    清单

    • 您的类文件在 /lib 或 /bin 下
      • 可以是那些下的子目录
      • json_serializable 不会在每个目录中搜索要生成的文件。
    • 为 json_annotation 添加了导入:
      • import 'package:json_annotation/json_annotation.dart';
    • 您在import 语句之后添加了一个part 指令
      • 您的part 文件以您的类文件名(不是类名本身)命名,并添加了g
      • 例如对于CacheItem 类...
      • cache-item.dart 类文件名 ...
      • part 'cache-item.g.dart'; 获取对应的part 指令。
      • part 指令不是以您的实际类命名的,而是类文件名。
    • 您已在类名上方添加@JsonSerializable()
    • 您已经为您的类创建了一个默认构造函数
      • 它可以是空的、有可选的命名参数或位置参数。
      • 只要您的类字段可访问(通过构造函数或公共 setter 和 getter),json_serializable 就可以处理它。 (即不只有 _private 属性和一个空的构造函数)
    • 您编写了两个调用私有存根方法的方法:
      • 工厂fromJson方法
        • 例如:factory CacheItem.fromJson(Map&lt;String,dynamic&gt; json) =&gt; _CacheItemFromJson(json)
      • toJson 方法
        • 例如:Map&lt;String,dynamic&gt; toJson() =&gt; _$CacheItemToJson(this)
      • 存根方法是私有的(以_ 下划线开头)
      • $tub 方法有$
      • 存根方法具有适当的 CaSe(即 Pascal Case
      • 存根 factory 提供 (Map&lt;String,dynamic&gt; json) 作为参数
      • 存根toJson()返回Map&lt;String,dynamic&gt;

    所有这些都完成后,尝试从项目根目录中的命令行或终端运行生成器...

    在颤振中:

    flutter pub run build_runner build

    在纯 Dart 中,这取决于您的版本,但其中之一应该可以工作:

    dart run build_runner build
    pub run build_runner build
    dart pub run build_runner build
    

    如果一切顺利,在您的项目文件资源管理器或Reload from disk 中单击,新文件应该会出现,例如上述示例中的cache-item.g.dart

    常见错误

    Bad state: Unexpected diagnostics:

    在运行 build_runner 时看到此输出可能是颤振和json_annotation 的问题,具体取决于analyzer 的不兼容版本。这发生在json_serializable 版本3.5 之前 需要dependency_override of analyzer 到 0.39.14 或 0.39.17。

    您的第一步应该是尝试最新版本的json_serilizable from pub.dev apparently doesn't have this dependency problem

    如果您无法升级 json_serializable,您可以尝试将覆盖线放在 dev_dependences 下方:

    dev_dependencies:
      build_runner: ^1.9.0
      flutter_test:
        sdk: flutter
      json_serializable: 3.3.0
      test: ^1.14.3
    
    dependency_overrides:
      analyzer: '0.39.14'
    

    [SEVERE] Nothing can be built, yet a build was requested.

    当我们在 pubspec.yaml 中为 json_annotation 添加依赖项但缺少 json_serializable 的依赖项/dev_dependency 时,执行 flutter pub run build_runner build 时可能会发生此错误:

    dependencies:
      flutter:
        sdk: flutter
      get:
      json_annotation: ^4.3.0
      some_other_packages:
    

    确保您已将 json_serializable 包添加为依赖项或 dev_dependency:

    dependencies:
      flutter:
        sdk: flutter
      get:
      json_annotation: ^4.3.0
    
    dev_dependencies:
      build_runner: ^2.1.4
      flutter_test:
        sdk: flutter
      json_serializable: ^6.0.1  #// ← do not forget
      test:
    

    Could not generate fromJsoncode forsomeField.

    如果您要对包含 someField 的类进行 json 序列化,该类是您创建的另一个自定义类的类型,您有 @JsonSerializable() 那个其他自定义类吗?

    @JsonSerializable(explicitToJson: true)
    class BuildingStatus {
      final Building building; // another custom class
    
      BuildingStatus(Building building);
    
      factory BuildingStatus.fromJson(Map<String,dynamic> json) => _$BuildingStatusFromJson(json);
      Map<String,dynamic> toJson() => _$BuildingStatusToJson(this);
    }
    
    
    /// This guy needs serialization too.
    @JsonSerializable()
    class Building {
      final String name;
    
      const Building(this.name);
    
      factory Building.fromJson(Map<String,dynamic> json) => _$BuildingFromJson(json);
      Map<String,dynamic> toJson() => _$BuildingToJson(this);
    }
    
    

    如果不序列化嵌套的 Building 类,我们会在运行 build_runner 时看到如下错误:

    Could not generate `fromJson` code for `building` because of type `Building`.
    

    “SomeNestedClass”的实例

    如果我们有嵌套的可序列化类,我们通常希望序列化以递归方式发生。即嵌套类也被序列化。

    为此,我们将使用 explicitToJson: true 注释我们的包含类,例如: @JsonSerializable(explicitToJson: true)

    所以当我们toJson() 我们的BuildingStatus 实例时,而不是得到:

    {"building": Instance of 'Building'}
    

    ...我们会得到:

    {"building": {"name": "Empire State"}}
    

    注意事项

    子类/父类

    如果您的类是父类的子类,并且您只想序列化子类的字段/属性,则可以仅注释子类。父类字段将自动找到并包含在为子类生成的类文件中。

    如果您希望能够同时分别序列化/反序列化父类和子类,请继续使用@JsonSerializable 注释基类/父类。

    例如文件名account.dart

    import 'package:json_annotation/json_annotation.dart';
    
    part 'account.g.dart';
    
    class AccountBase {
      int created;
      String username;
      String password;
    }
    
    @JsonSerializable()
    class Account extends AccountBase {
      int id;
    
      Account();
    
      factory Account.fromJson(Map<String,dynamic> json) => _$AccountFromJson(json);
      Map<String,dynamic> toJson() => _$AccountToJson(this);
    }
    

    生产:

    // GENERATED CODE - DO NOT MODIFY BY HAND
    
    part of 'account.dart';
    
    // **************************************************************************
    // JsonSerializableGenerator
    // **************************************************************************
    
    Account _$AccountFromJson(Map<String, dynamic> json) {
      return Account()
        ..created = json['created'] as int
        ..username = json['username'] as String
        ..password = json['password'] as String
        ..id = json['id'] as int;
    }
    
    Map<String, dynamic> _$AccountToJson(Account instance) => <String, dynamic>{
          'created': instance.created,
          'username': instance.username,
          'password': instance.password,
          'id': instance.id,
        };
    

    参考和文档

    示例

    import 'package:json_annotation/json_annotation.dart';
    
    part 'cache-item.g.dart';
    
    @JsonSerializable()
    class CacheItem {
      int created;
      String keywords;
      String response;
    
      CacheItem(this.created, this.keywords, this.response);
    
      factory CacheItem.fromJson(Map<String,dynamic> json) => _$CacheItemFromJson(json);
      Map<String,dynamic> toJson() => _$CacheItemToJson(this);
    }
    

    输出

    // GENERATED CODE - DO NOT MODIFY BY HAND
    
    part of 'cache-item.dart';
    
    // **************************************************************************
    // JsonSerializableGenerator
    // **************************************************************************
    
    CacheItem _$CacheItemFromJson(Map<String, dynamic> json) {
      return CacheItem(
        json['created'] as int,
        json['keywords'] as String,
        json['response'] as String,
      );
    }
    
    Map<String, dynamic> _$CacheItemToJson(CacheItem instance) => <String, dynamic>{
          'created': instance.created,
          'keywords': instance.keywords,
          'response': instance.response,
        };
    
    

    示例构造函数变体

    除了构造函数缺少一些字段并且response 是可选的之外,此示例与上面的示例相同。

    没关系。

    生成器将在实例化对象后仅使用公共(隐式)设置器来分配值。

    import 'package:json_annotation/json_annotation.dart';
    
    part 'cache-item.g.dart';
    
    @JsonSerializable()
    class CacheItem {
      int created;
      String keywords;
      String response;
    
      CacheItem({this.response});
    
      factory CacheItem.fromJson(Map<String,dynamic> json) => _$CacheItemFromJson(json);
      Map<String,dynamic> toJson() => _$CacheItemToJson(this);
    }
    

    输出

    // GENERATED CODE - DO NOT MODIFY BY HAND
    
    part of 'cache-item.dart';
    
    // **************************************************************************
    // JsonSerializableGenerator
    // **************************************************************************
    
    CacheItem _$CacheItemFromJson(Map<String, dynamic> json) {
      return CacheItem(
        response: json['response'] as String,
      )
        ..created = json['created'] as int
        ..keywords = json['keywords'] as String;
    }
    
    Map<String, dynamic> _$CacheItemToJson(CacheItem instance) => <String, dynamic>{
          'created': instance.created,
          'keywords': instance.keywords,
          'response': instance.response,
        };
    
    

    【讨论】:

    • 这个真的很有帮助,最重要的是不要使用额外的依赖项,只需使用@Baker 建议的内容。 +1
    • 我已经检查了一切,并确认不生成那些模型-json转换方法
    • 有史以来最好的答案!
    • 就我而言,它是关于 .g.dart 文件名;我试图输入“xx_quentity_model.g.dart”,但我的 dart 文件名是“xx_quantity_model.dart”所以,我的 .g.dart 文件没有生成,所以如果你在检查列表中没有发现任何错误,也许你可以控制.g.dart 文件名(用于类型错误)。
    【解决方案2】:

    构造函数的参数不应该是可选的

    User({this.firstName, this.lastName, this.dateOfBirth});
    

    它们应该是强制性的:

    User(this.firstName, this.lastName, this.dateOfBirth);
    

    还有部分

    'user.g.dart';
    

    应该匹配大写用户类:

    part 'User.g.dart';
    

    【讨论】:

    • 我试过使用可选参数,效果很好。快乐飘飘。
    • 强制参数是正确的,但大写字母并没有真正起作用。但是争论。
    • 谢谢,可选参数构造函数对我来说似乎是个问题。
    • 如果你在一个名为logged_user.dart的文件中有一个类似LoggedUser的类,那么使用part 'logged_user.g.dart'
    • 如果您在项目中使用包,首先需要转到该包路径并运行“flutter pub run build_runner build”
    【解决方案3】:

    尝试运行

    >flutter packages pub run build_runner build --delete-conflicting-outputs
    

    【讨论】:

      【解决方案4】:

      文件名、类和part 'Book.g.dart'; 应该都匹配。

      【讨论】:

      • 您对 Jalil 回答的评论表明您可以使用可选参数构造函数。您有机会将代码放入此答案吗?因为从选项更改为必需的参数是唯一让这对我有用的事情。
      【解决方案5】:

      我遇到了以下错误

      错误

      [WARNING] json_serializable:json_serializable on lib/day10/models/sentence.dart:
      Missing "part 'sentence.g.dart';".
      

      我注意到我必须将模型文件中的 part 'Sentence.g.dart'; 更改为 part 'sentence.g.dart';,换句话说,我必须将其小写。

      【讨论】:

        【解决方案6】:

        我知道,在运行命令之前必须保存文件
        flutter packages pub run build_runner build

        我知道答案似乎很简单。

        【讨论】:

        • 我进行了一些编辑,以减少您描述自己的问题的印象(这里的用户很容易混淆)。我注意到有问题的文件没有明确标识。您可能想要更明确。否则感谢您的贡献。
        • 刚刚安装 vs code 并尝试过的情况对我来说完全一样 :( 感谢您的提示
        【解决方案7】:

        就我而言,我必须添加 hive_generator 包以及 build_runner 包。 如果您的模型类名称是例如 transaction.dart,那么它将是这样的 - part 'transaction.g.dart' 运行命令—— flutter packages pub run build_runner build它会为你生成交易模型。

        【讨论】:

          【解决方案8】:

          就我而言,问题在于我拼错了方法名称。我写的是 formJson 而不是 fromJson。

          factory MyClass.formJson(Map<String, dynamic> json) =>
          _$MyClassFromJson(json);
          

          应该是:

          factory MyClass.fromJson(Map<String, dynamic> json) =>
          _$MyClassFromJson(json);
          

          【讨论】:

            【解决方案9】:

            添加

            json_serializable: ^6.0.0
            

            到 dev_dependencies 为我解决它

            【讨论】:

              猜你喜欢
              • 2021-09-07
              • 2021-11-11
              • 2021-05-20
              • 2020-04-27
              • 2021-09-26
              • 2018-05-29
              • 1970-01-01
              • 2018-11-26
              • 1970-01-01
              相关资源
              最近更新 更多