Flutter JSON 序列化 - 不生成 *.g.dart 文件
Posted
技术标签:
【中文标题】Flutter JSON 序列化 - 不生成 *.g.dart 文件【英文标题】:Flutter JSON Serialization - Not generating *.g.dart files 【发布时间】:2020-02-10 02:47:10 【问题描述】:我是 Flutter 的新手,目标是序列化包含其他较小对象的复杂 JSON 对象。
使用json_serializable: ^2.0.0
和pubspec.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
谁能让我知道我在这里缺少什么。谢谢
【问题讨论】:
【参考方案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<String,dynamic> json) => _CacheItemFromJson(json)
toJson
方法
例如:Map<String,dynamic> toJson() => _$CacheItemToJson(this)
存根方法是私有的(以_
下划线开头)
$tub 方法有$
存根方法具有适当的 CaSe(即 Pascal Case)
存根 factory
提供 (Map<String,dynamic> json)
作为参数
存根toJson()
返回Map<String,dynamic>
所有这些都完成后,尝试从项目根目录中的命令行或终端运行生成器...
在颤振中:
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 for
someField.
如果您要对包含 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,
;
参考和文档
示例project on github,/bin/下的相关文件和pubspec.yaml中的包 Flutter & Json Json_Serializable package Example 来自软件包作者示例
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 为我解决它
【讨论】:
以上是关于Flutter JSON 序列化 - 不生成 *.g.dart 文件的主要内容,如果未能解决你的问题,请参考以下文章