在〈JSON 與 dart:convert〉中的範例,必須自行實作 User
類別的 fromJson
、toJson
的內容,這個動作蠻無趣,只是一些對照的動作,你可以透過套件來自動產生這些內容,例如 json_serializable
。
json_serializable
透過 json_annotation
標註的資訊,結合 build_runner
來自動產生程式碼,因此必須在 pubspec.yaml 中加入:
dependencies:
json_annotation: ^3.0.1
dev_dependencies:
build_runner: ^1.10.0
json_serializable: ^3.4.1
以〈JSON 與 dart:convert〉中的範例來說,接著你可以定義 user.dart:
import 'package:json_annotation/json_annotation.dart';
part 'user.g.dart'; // 這個檔案的程式碼是 User 定義的一部份,它稍後才會建構產生
@JsonSerializable() // 標註這個類別中的程式碼要自動產生
class User {
String name;
int age;
User({this.name, this.age});
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
Map<String, dynamic> toJson() => _$UserToJson(this);
}
接著執行 flutter packages pub run build_runner build
,建構出 user.g.dart,內容會是:
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'user.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
User _$UserFromJson(Map<String, dynamic> json) {
return User(
name: json['name'] as String,
age: json['age'] as int,
);
}
Map<String, dynamic> _$UserToJson(User instance) => <String, dynamic>{
'name': instance.name,
'age': instance.age,
};
接下來使用的方式就跟〈JSON 與 dart:convert〉中的範例相同:
var json = jsonEncode(User(name: 'Justin', age: 40));
var user = User.fromJson(jsonDecode(json));
print(json);
print(user);
在產生的 user.g.dart 中可以看到,預設會使用 User
的欄位名稱來作為 Map
的 key,如果呼叫的 API 使用的 key 與欄位名稱不同,可以使用 @JsonKey
來標註,例如:
import 'package:json_annotation/json_annotation.dart';
part 'user.g.dart';
@JsonSerializable()
class User {
String name;
int age;
// 標註 API 的 key 與欄位名稱的對應
@JsonKey(name: 'address')
String email;
User({this.name, this.age, this.email});
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
Map<String, dynamic> toJson() => _$UserToJson(this);
}
如此一來,產生的 user.g.dart 會是:
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'user.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
User _$UserFromJson(Map<String, dynamic> json) {
return User(
name: json['name'] as String,
age: json['age'] as int,
email: json['address'] as String,
);
}
Map<String, dynamic> _$UserToJson(User instance) => <String, dynamic>{
'name': instance.name,
'age': instance.age,
'address': instance.email,
};
如果只是命名上 Snake case 與 Camel case 的差別,可以透過 @JsonSerializable(fieldRename: FieldRename.snake)
來標註,就不用逐一在各欄位上使用 @JsonKey
標註名稱了,其他還有可設置的特性,詳情可查看 json_serializable
的文件。
如果你持續地在修改模型,也可以執行 flutter package pub run build_runner watch
,這會持續監看模型的內容是否有更動,自動產生新的程式碼。