JsonSerializable の Tips (おまけで freezed も)

公開:2020/12/02
更新:2020/12/02
5 min読了の目安(約4500字TECH技術記事

はじめに

こんにちは。やまたつです!
アプリエンジニアとして働いており、現在 Flutter での開発にハマっています。

JsonSerializable を使った開発をしていたのですが、最近 fieldRename: FieldRename.snake を知って、歓喜し、今までの手打ちは何だったんだと少しだけ悲しくなりました。。。
いつも @JsonKey(name: 'hoge_id') と記述していたのにそれが必要なくなりました!

他のエンジニア方が自分と同じ轍を踏まないように、この記事を残しておきます🚀

JsonSerializable

JsonSerializable とは、json からオブジェクト(class) への変換、 オブジェクトから json への変換を簡単にしてくれるパッケージです。
以下のコードは JsonSerializable の Example です。
@JsonSerializable() のところにプロパティを指定できます。Example では nullable: false がセットされています。

import 'package:json_annotation/json_annotation.dart';

part 'example.g.dart';

(nullable: false)
class Person {
  final String firstName;
  final String lastName;
  final DateTime dateOfBirth;
  Person({this.firstName, this.lastName, this.dateOfBirth});
  factory Person.fromJson(Map<String, dynamic> json) => _$PersonFromJson(json);
  Map<String, dynamic> toJson() => _$PersonToJson(this);
}

JsonSerializable のプロパティ

@JsonSerializable のプロパティにはいくつか種類があり、最近知った fieldRename: FieldRename.snake もその一つです。
気になったものだけ紹介します。

  1. cheked
    デフォルトは false
    true にすると fromJson 中で例外がスローされた時に、CheckedFromJsonException がスローされます。例えば、型を間違って指定してしまった時など、fromJson 中にエラーが発生し、どこの型が間違ったのか分からなくなります。checked を true にしておくとコンソールにどのプロパティで落ちたのか確認することができるので便利です。
  2. createFactory
    デフォルトは true
    true の場合、生成されたファイルに _$〇〇FromJson メソッドが作成されます。
  3. createToJson
    デフォルトは true
    true にすると、生成されたファイルに toJson メソッドが作成されます。
  4. disallowUnrecognizedKeys
    デフォルトは false
    false の時は認識できなかったキーを無視します。
    true の時は認識できないキーがあった場合、UnrecognizedKeysException をスローします。
    false の設定で良いかと思います。
  5. field_rename
    デフォルトは none
    enum で定義してあり、ケバブケース、スネークケース、パスカルケースに対応しているようです。
    スネークケースに対応しているのはとても嬉しいです☺️
    また、プロパティに直接 @JsonKey(name: 'user_id') を記述していると、@JsonKey を優先して、json をパースします。
    以下は、FieldRename の enum の定義です。
enum FieldRename {
  /// Use the field name without changes.
  none,

  /// Encodes a field named `kebabCase` with a JSON key `kebab-case`.
  kebab,

  /// Encodes a field named `snakeCase` with a JSON key `snake_case`.
  snake,

  /// Encodes a field named `pascalCase` with a JSON key `PascalCase`.
  pascal
}

JsonSerializable のプロパティの指定の仕方

class に JsonSerializable() を記述

(
 checked: true,
 fieldRename: FieldRename.snake,
)
class User {
 ~~~~
}

build.yaml をプロジェクトにトップの階層に配置

build.yaml を配置しておくと、全ての JsonSerializable の class に適用されます。
ちなみにトップの階層とは、 pubspec.yaml があるところです。

JsonSerializableBuild configuration の欄にも詳細が記述してあります。
自分は今度から以下の build.yaml を配置しようと思います!!!

build.yaml
targets:
  $default:
    builders:
      json_serializable:
        options:
          # Options configure how source code is generated for every
          # `@JsonSerializable`-annotated class in the package.
          #
          # The default value for each is listed.
          any_map: false
          checked: true  # デフォルトから変更
          create_factory: true
          create_to_json: true
          disallow_unrecognized_keys: false
          explicit_to_json: false
          field_rename: snake # デフォルトから変更
          generic_argument_factories: false
          ignore_unannotated: false
          include_if_null: true
          nullable: true

全てのファイルに @JsonSerializable を書くのは面倒なので、 build.yaml を配置するのがおすすめ!

おまけ freezed編

freezed を使っていても build.yaml を配置して、 snakeケースに対応できます!

freezed では @JsonSerializable を指定する箇所はコンストラクターの上になります。


abstract class Example with _$Example {
  (explicit_to_json: true)
  factory Example((name: 'my_property') SomeOtherClass myProperty) = _Example;

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

@JsonKey も指定できます!


abstract class Example with _$Example {
  factory Example((name: 'my_property') String myProperty) = _Example;

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

終わりに

JsonSerializable の説明をちゃんと見ておけば、fieldRename: FieldRename.snake にも早く気づけたのにな!!!と思いましたが、いろいろ調べるきっかけになったし、これからの開発がより上手くいくので問題ないです!
Flutter 楽しい!!!

みなさんの Tips も知りたいので良かったらコメント欄で教えていただけると嬉しいです!
間違っている箇所などありましたら、教えていただきたいです!
読んでいただきありがとうございました!

初めての Zenn への投稿でしたが、書きやすくて良いですね☺️