# 好用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; ``` ![](https://i.imgur.com/brLsa5g.png) ### 程式範例 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`