# 好用package - json_annotation/json_serializable/build_runner 介紹
## JSON格式介紹
JSON是JavaScript Object Notation的縮寫
```json
{
"users": [
{
"user_name": "a",
"age": 9,
"height" 139
},
{
"user_name": "b",
"age": 19,
"height" 159.2
},
{
"user_name": "c",
"age": 29,
},
]
}
```
## json_annotation
```
flutter pub add json_annotation
```
[官網](https://pub.dev/packages/json_annotation)
### 教學
#### @JsonSerializable
需要進行生成`XXXXXFromJson`與`XXXXXToJson`這兩個方法的地方進行標記。
#### @JsonKey
假如傳進來的key是user_name與程式裡面定義的變數名稱name不同,可以加上@JsonKey(name: 'name')進行轉換,再重新生成一次就可以
```dart
@JsonKey(name: 'user_name')
String name;
```

### 程式範例
user_model.dart
```dart
import 'package:json_annotation/json_annotation.dart';
//輸入指令後會自動生成此檔案
part 'test_model.g.dart';
//需要進行自動生成轉換JSON的方法
@JsonSerializable()
class Test {
String name;
int? age;
double? height;
Test({
required this.name,
this.age,
this.height
});
}
//沒有@JsonSerializable(),所以不會轉換
String getAge(int? age) {
if (age == null || age > 18) {
return '年齡能吃ㄇ';
}
return age.toString() + ' 歲';
}
String getHeight(double? height) {
if (height == null) {
return '不想說';
}
return height.toString() + ' 公分';
}
```
雖然會有錯誤提示(找不到`part 'user_model.g.dart'`因為我們還沒有這一個檔案)但可以先行忽略,cmd 輸入
```
dart run build_runner watch
```
就會生成同一資料夾下`recipe_model.g.dart` 這一個檔案,此檔案內就會**自動生成`UserTestFromJson`與`UserTestToJson`這兩個方法**。
接著只要將這兩個方法寫入`user_model.dart` 內就可以使用了,如下:
```dart
import 'package:json_annotation/json_annotation.dart';
part 'test_model.g.dart';
@JsonSerializable()
class Users {
List<User>? users;
Users({this.users});
//---這一段是生成test_model.g.dart後需要自己進行添加的--
factory Users.fromJson(Map<String, dynamic> json) =>
_$UsersFromJson(json);
Map<String, dynamic> toJson() => _$UsersToJson(this);
//-----------------------------------------------------
}
@JsonSerializable()
class User {
String name;
int? age;
double? height;
User({required this.name, this.age, this.height});
//---這一段是生成test_model.g.dart後需要自己進行添加的--
factory User.fromJson(Map<String, dynamic> json) =>
_$UserFromJson(json);
Map<String, dynamic> toJson() => _$UserToJson(this);
//-----------------------------------------------------
}
//沒有@JsonSerializable(),所以不會轉換
String getAge(int? age) {
if (age == null || age > 18) {
return '年齡能吃ㄇ';
}
return age.toString() + ' 歲';
}
String getHeight(double? height) {
if (height == null) {
return '不想說';
}
return height.toString() + ' 公分';
}
```
若有一JSON資料想進行轉換,可以使用以下方式
```dart
late Users _currentRecipes1;
@override
void initState() {
super.initState();
loadUsers();
}
Future loadUsers() async {
final jsonString = await rootBundle.loadString('assets/users.json');
setState(() {
_currentRecipes1 = Users.fromJson(jsonDecode(jsonString));
});
}
```
## json_serializable
共執行build_runner時使用
```
flutter pub add json_serializable
```
[官網](https://pub.dev/packages/json_serializable)
## build_runner
是一個所有代碼生成器都需要的包,以便構建**.part文件類。(只會在開發環境下運行)
```
dart pub add dev:build_runner
```
[官網](https://pub.dev/packages/build_runner)
```
flutter pub run build_runner watch
```
## 相關除錯教學
1. Unable to generate package graph, no `/.dart_tool/flutter_gen/pubspec.yaml` found.
```
unhandled exception:
Bad state: Unable to generate package graph, no `.../.dart_tool/flutter_gen/pubspec.yaml` found.
#0 _pubspecForPath (package:build_runner_core/src/package_graph/package_graph.dart:232:5)
#1 _parsePackageDependencies (package:build_runner_core/src/package_graph/package_graph.dart:206:21)
#2 PackageGraph.forPath (package:build_runner_core/src/package_graph/package_graph.dart:101:33)
<asynchronous suspension>
#3 main (.../flutter/.pub-cache/hosted/pub.dartlang.org/build_runner-2.3.2/bin/build_runner.dart:27:30)
<asynchronous suspension>
```
解法:將`pubspec.yaml`內的`generate: true`註解
```
flutter:
# generate: true
```
2. Conflicting outputs were detected and the build is unable to prompt for permission
```
[INFO] Checking for unexpected pre-existing outputs....
[INFO] Found 11 declared outputs which already exist on disk. This is likely because the`.dart_tool/build` folder was deleted, or you are submitting generated files to your source repository.
[SEVERE] Conflicting outputs were detected and the build is unable to prompt for permission to remove them. These outputs must be removed manually or the build can be run with `--delete-conflicting-outputs`. The outputs are: lib/models/peopleList.g.dart
```
解法:將指令調整為以下
```
dart run build_runner watch --delete-conflicting-outputs
```
## 參考資料
https://ithelp.ithome.com.tw/articles/10252453?sc=rss.iron
https://swagger.io/docs/specification/adding-examples/
###### tags: `flutter`