【Flutter】自由自在にJsonを操るTips集

# はじめに
FlutterでJsonを扱うならおそらくほとんどの人が使っている[json_serializable](https://pub.dev/packages/json_serializable)ですが、
開発で扱う上でこういうのできないんだろうか？と疑問に思い、調べたことを紹介していこうと思います。
ネタが増えたら随時更新していきたいと思います。

# インストール
```
flutter pub add json_annotation
```
```
flutter pub add --dev build_runner
```
```
flutter pub add --dev json_serializable  
```

# Jsonのキーの名前を変えたい

対象のフィールドに`@JsonKey(name: 'xxxx')`をつけると、キーを変更できます。

```dart
import 'package:json_annotation/json_annotation.dart';

part 'author.g.dart';

@JsonSerializable()
class Author {
  @JsonKey(name: 'author_id')
  final String authorId;
  final String name;

  Author({
    required this.authorId,
    required this.name,
  });

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

  Map<String, dynamic> toJson() => _$AuthorToJson(this);
}
```

```dart:Jsonデータ
  final json = {
    'author_id': "0001",
    'name': "Tanaka Taro",
  };
```

フィールドすべてを一括で変更したい場合はクラス名の上に、`@JsonSerializable(fieldRename: FieldRename.snake)`を付けます。
```dart
import 'package:json_annotation/json_annotation.dart';

part 'author.g.dart';

@JsonSerializable(fieldRename: FieldRename.snake)
class Author {
  final String authorId;
  final String name;

  Author({
    required this.authorId,
    required this.name,
  });

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

  Map<String, dynamic> toJson() => _$AuthorToJson(this);
}
```

# nullの場合はJsonに出力しないようにする
nullの場合にJsonに出力したくない場合は`@JsonKey(includeIfNull: false)`をフィールドに付けます。

```dart
import 'package:json_annotation/json_annotation.dart';

part 'user.g.dart';

@JsonSerializable()
class User {
  int id;
  String name;
  @JsonKey(includeIfNull: false)
  String email;

  User({this.id, this.name, this.email});

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

  Map<String, dynamic> toJson() => _$UserToJson(this);
}

```

```
  final yamada = User(
    id: "0001",
    name: "Yamada Dai",
    email: "yamada@example.com",
  );
  final tanaka = User(
    id: "0002",
    name: "Tanaka Hiroshi",
  );

　// {id: 0001, name: Yamada Dai, email: yamada@example.com}
  print(yamada.toJson());
　// {id: 0002, name: Tanaka Hiroshi}
  print(tanaka.toJson());
```

# デフォルト値を設定したい

APIレスポンスがnullで返ってきて、アプリケーションではnon nulllで扱いたいときに、`@JsonKey(defaultValue: '')`で初期値を設定できます。

```dart
import 'package:json_annotation/json_annotation.dart';

part 'food.g.dart';

@JsonSerializable()
class Food {
  final String id;
  @JsonKey(defaultValue: '')
  final String name;

  Food({
    required this.id,
    required this.name,
  });
  factory Food.fromJson(Map<String, dynamic> json) => _$FoodFromJson(json);

  Map<String, dynamic> toJson() => _$FoodToJson(this);
}
```

```dart:Jsonサンプル
  // キーがなくても大丈夫
  final json1 = {
    "id": "0001",
  };
  final json2 = {
    "id": "0001",
    "name": null,
  };

```


# List型をJsonから変換時、アイテムがない場合にエラーになる
これも同じくdefaultValueで解決できました。

```dart
import 'package:json_annotation/json_annotation.dart';

part 'example.g.dart';

@JsonSerializable()
class Example {
  @JsonKey(defaultValue: [])
  List<String> items;

  Example({required this.items});

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

  Map<String, dynamic> toJson() => _$ExampleToJson(this);
}
```

# オブジェクトが入れ子になったクラス

複雑なJsonのパースは、専用のメソッドを定義し、`@JsonKey(fromJson: _addressFromJson, toJson: _addressToJson)`という形で指定することで、パースできるようになります。

```dart
import 'package:json_annotation/json_annotation.dart';

@JsonSerializable()
class Person {
  String name;
  int age;
  @JsonKey(fromJson: _addressFromJson, toJson: _addressToJson)
  Address address;

  Person({this.name, this.age, this.address});

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

  Map<String, dynamic> toJson() => _$PersonToJson(this);

  static Address _addressFromJson(Map<String, dynamic> json) {
    return json == null ? null : Address.fromJson(json);
  }

  static Map<String, dynamic> _addressToJson(Address address) =>
      address?.toJson();
}

@JsonSerializable()
class Address {
  String street;
  String city;

  Address({this.street, this.city});

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

  Map<String, dynamic> toJson() => _$AddressToJson(this);
}

```

# Jsonに含めたくない
Jsonに含めたくない場合は`@JsonKey(ignore: true)`を指定しましょう。

```dart
import 'package:json_annotation/json_annotation.dart';

part 'user.g.dart';

@JsonSerializable()
class User {
  int id;
  String name;
  @JsonKey(ignore: true)
  String email;

  User({this.id, this.name, this.email});

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

  Map<String, dynamic> toJson() => _$UserToJson(this);
}
```

# おわりに
[JsonKey](https://pub.dev/documentation/json_annotation/latest/json_annotation/JsonKey-class.html)には他にも設定できる値があり、カスタマイズしていけそうです。
また、開発していく上で使えそうなものがあれば、記事を更新していきたいと思います！