freezed・JsonSerializable　完全攻略

## はじめに
Flutterで開発するにあって無くてはならないpackageであるfreezedを改めてまとめておきます
コピペするだけで使えるようにしておきますので使用してみてください

ちゃんと知りたい人は公式ドキュメントをご覧ください
https://pub.dev/packages/freezed

なるべく楽したい人は↓へ

## パッケージ導入
何も考えず下記のコマンドを1つずつ実行してpackageを入れてください
全部使います
```
flutter pub add freezed_annotation
flutter pub add --dev build_runner
flutter pub add --dev freezed
flutter pub add json_annotation
flutter pub add --dev json_serializable
flutter pub add analyzer
flutter pub get
```

## ファイル設定
```
(project)
 - analysis_options.yaml // 編集するファイル
 - build.yaml // 追加するファイル
 - pubspec.yaml // このファイルと同じ階層にファイル作ってください
```

何も考えずにanalysis_options.yamlにコピペして追加してください
自動生成されたファイルはlintエラーになるのでこの対応が必須です
```analysis_options.yaml
analyzer:
  errors:
    invalid_annotation_target: ignore
  exclude:
    - "**/*.g.dart"
    - "**/*.freezed.dart"
```

何も考えずにbuild.yamlにコピペして追加してください
build.yamlがない場合は新規作成してください
```build.yaml
targets:
  $default:
    builders:
      source_gen|combining_builder:
        options:
          build_extensions:
            '^lib/{{}}.dart': 'lib/generated/{{}}.g.dart'
      freezed:
        options:
          build_extensions:
            '^lib/{{}}.dart': 'lib/generated/{{}}.freezed.dart'
```

pubspec.yamlのgenerateがtrueになっているとファイルの自動生成に失敗するのでご注意を
```pubspec.yaml
// generate: true
generate: false 
```
## モデルクラスの作成
APIでもSQLでも使えるようにモデルクラスを作成しました
何も考えずにコピペして追加してください
jsonのkeyを指定したり、defaultを指定できるのでソースを確認してみてください

freezedとJsonSerializableの2種類があるのですが、
値を編集する動的なモデルクラスならfreezed
値を参照する静的なモデルクラスならJsonSerializablを使用してください
めんどくさい場合はfreezedに統一してください
```lib/model/notice.dart
import 'package:freezed_annotation/freezed_annotation.dart';

part '../../generated/model/notice.freezed.dart';
part '../../generated/model/notice.g.dart';

/// お知らせフラグ
class NoticeFlag {
  /// 既読フラグ(0=未読)
  static const int unread = 0;

  /// 既読フラグ(1=既読)
  static const int read = 1;
}

@freezed
class Notice with _$Notice {
  /// コンストラクタ
  const factory Notice({
    /// お知らせID
    required int id,

    /// タイトル
    required String title,

    /// メッセージ内容
    required String message,

    ///　既読フラグ(0=未読、1=既読)
    @Default(0) int isUnread,
  }) = _Notice;

  /// json -> モデルクラス
  factory Notice.fromJson(Map<String, dynamic> json) => _$NoticeFromJson(json);

  // freezedはtoJsonを標準装備している
  // Map<String, dynamic> toJson()

}

@JsonSerializable()
class NoticeList {
  // lintツール sort_unnamed_constructors_first
  const NoticeList({required this.noticeList});

  // lintツール　sort_constructors_first
  /// json -> モデルクラス
  factory NoticeList.fromJson(Map<String, dynamic> json=>
      _$NoticeListFromJson(json);

  /// お知らせリスト（json key指定）
  @JsonKey(name: 'notice_list')
  final List<Notice> noticeList;

  /// モデルクラス -> json
  Map<String, dynamic> toJson() => _$NoticeListToJson(this);
}
```

## コマンド実行
何も考えすに下記のコマンド実行してください

普段使うなら一番下のコマンドだけで大丈夫です
しかしたまにコンフリクトが起きていたり、ファイルの差分や読み込みがうまくいかないことがあるので、
その場合は下記のコマンド全て実行するとほぼ解決します
（gitで管理しているとよくある）

ちなみに自動生成されるファイルはlib/generated/model配下にあるのでご確認ください
```
rm pubspec.lock
flutter clean
flutter pub get
flutter pub run build_runner build --delete-conflicting-outputs
```

## 動作確認
json←→モデルクラスの変換を実装しているので、下記を参考にしていただければ大体解決するかと思います
copyWithはfreezedでしか使えないのでご注意を

めんどくさい場合はmain()で実行してください
```
  /// Noticeモデル
  // json生成
  final noticeJson = <String, dynamic>{
    'id': 0,
    'title': 'タイトル0',
    'message': 'メッセージ0',
  };
  debugPrint('noticeJson = $noticeJson');
  // -> noticeJson = {id: 0, title: タイトル0, message: メッセージ0}

  // json -> Noticeモデル
  final noticeFromJson = Notice.fromJson(noticeJson);
  debugPrint('noticeFromJson = $noticeFromJson');
  // -> noticeFromJson = Notice(id: 0, title: タイトル0, message: メッセージ0, isUnread: 0)

  // noticeFromJsonの値を変更してコピーする
  final noticeCopyWith = noticeFromJson.copyWith(isUnread: NoticeFlag.read);
  debugPrint('noticeCopyWith = $noticeCopyWith');
  // -> noticeCopyWith = Notice(id: 0, title: タイトル0, message: メッセージ0, isUnread: 1)

  // Noticeモデル生成
  const noticeModel = Notice(
    id: 1,
    title: 'タイトル1',
    message: 'メッセージ1',
    isUnread: NoticeFlag.read,
  );
  debugPrint('noticeModel = $noticeModel');
  // -> noticeModel = Notice(id: 1, title: タイトル1, message: メッセージ1, isUnread: 1)

  // Noticeモデル -> json
  final noticeToJson = noticeModel.toJson();
  debugPrint('noticeToJson = $noticeToJson');
  // -> noticeToJson = {id: 1, title: タイトル1, message: メッセージ1, isUnread: 1}

  /// NoticeListモデル
  // json生成
  final noticeListJson = <String, dynamic>{
    'notice_list': [noticeJson],
  };
  debugPrint('noticeListJson = $noticeListJson');
  // -> noticeListJson = {notice_list: [{id: 0, title: タイトル0, message: メッセージ0}]}

  // json -> NoticeListモデル
  final noticeListFromJson = NoticeList.fromJson(noticeListJson);
  // NoticeListモデル -> json
  debugPrint('noticeListFromJson = ${noticeListFromJson.toJson()}');
  // -> noticeListFromJson = {notice_list: [Notice(id: 0, title: タイトル0, message: メッセージ0, isUnread: 0)]}
```

## 締め
公式ドキュメントを確認しよう
https://pub.dev/packages/freezed