🔍

【Flutter】マクロ対応のデータクラスを作った

2024/05/25に公開

こんにちは。広瀬マサルです。

Google I/O 2024でFlutterのマクロの発表がありましたね。

Masamuneフレームワークは「アプリ開発のすべてをマクロでサポートする」ことを最終的な目標として開発を続けていました。

マクロへの対応を行うためにこれまでfreezedjson_serializableに頼っていたデータクラスやJsonの変換をMasamuneフレームワーク内で行うことにしました。

使い方をまとめたので興味ある方はぜひ使ってみてください!

💡 2024年6月時点ではDartのマクロ機能はプレビュー版です。
破壊的な変更が続くことが予想されるため当パッケージも仕様が大幅に変更される可能性が高いです。ご注意ください。

katana_value

https://pub.dev/packages/katana_value

はじめに

Dartのマクロ機能を利用しイミュータブルなデータクラスの作成を可能にします。

比較演算子への対応およびcopyWithの実装、toStringの整備がアノテーションを付与するだけで可能になります。

また合わせてJsonからの変換Jsonへの変換も可能にします。

下記のように簡単に定義可能です。


class Person {
	Person({
	  required String name,
	  int? age,
	});
}

下記のように利用することが可能です。

final person = Person(name: "Kanimiso");
final copied = person.copyWith(age: 20);
final json = person.toJson();
print(json); // {name: "Kanimiso", age: 20}

事前準備

💡 2024年6月時点で必要な準備です。マクロがStableになった場合必要ありません。
  1. Dart dev channel もしくは Flutter master channel に変更します。

  2. dart --versionを実行しDartのバージョンを3.5.0-152より新しくします。

  3. pubspec.yamlのDartSDKのバージョンを^3.5.0-152に設定します。

  4. analysis_options.yamlに下記のコードを追加します。

    analyzer:
     enable-experiment:
       - macros
    
  5. dart run --enable-experiment=macros bin/my_app.dart

インストール

下記パッケージをインポートします。

flutter pub add katana_value

実装

データクラスの作成

@DataValueのアノテーションをデータクラスにしたいクラスに付与します。

コンストラクタに必要なフィールドの型と名前を定義します。これだけでデータクラスが作成されます。


class Person {
	Person({
	  required String name,
	  int? age,
	});
}

データクラスの利用

定義したクラスはそのままオブジェクト化を行うことができます。

final person = Person(name: "Kanimiso", age: 20);

またcopyWithtoJsonfromJsonなどのメソッドを利用することが可能です。

final json = {"name": "Kanimiso", "age": 20};
final person = Person.fromJson(json);
print(person.toString()); // Person(name: Kanimiso, age: 20)

final copied = person.copyWith(age: 30);
print(copied.toJson()); // {"name": "Kanimiso", "age": 30};

Jsonに変換可能な型

初期状態では下記の型が変換可能です。(Nullable含む)

  • int
  • double
  • num
  • String
  • bool
  • Iterable
  • List
  • Set
  • Map

新しいJson変換型への対応

上記の型が初期で利用可能ですが新しくJsonの変換に対応したい型がある場合はDataValueJsonConverterを利用します。

  1. DataValueJsonConverterを継承したクラスを作成します。

    class ModelCounterJsonConverter extends DataValueJsonConverter {
    	const ModelCounterJsonConverter();
    	
    	
      Map<String, dynamic>? toJson(dynamic value) {
        if (value is ModelCounter) {
          return value.toJson();
        }
        return null;
      }
    
      
      dynamic fromJson(String key, Map<String, dynamic> json) {
        final map = json[key];
        if(map is Map<String, Object?> && map["#type"] == "ModelCounter") {
          return PersonBase.fromJson(map);
        }
        return null;
      }
    }
    
  2. 作成したクラスをmainメソッド内などアプリ起動時にDataValueJsonConverter.registerで登録します。

    void main(){
      DataValueJsonConverter.register(const ModelCounterJsonConverter());
    }
    

実行

💡 2024年6月時点で必要な準備です。マクロがStableになった場合必要ありません。

実行には下記のコマンドを利用します。

dart run --enable-experiment=macros bin/my_app.dart

おわりに

自分で使う用途で作ったものですが実装の思想的に合ってそうならぜひぜひ使ってみてください!

また、こちらにソースを公開しているのでissueやPullRequestをお待ちしてます!

また仕事の依頼等ございましたら、私のTwitterWebサイトで直接ご連絡をお願いいたします!

https://mathru.net/ja/contact

GitHub Sponsors

スポンサーを随時募集してます。ご支援お待ちしております!

https://github.com/sponsors/mathrunet

Discussion