JSONと不変オブジェクトへのシリアル化。Flutterのbuilt_valueパッケージについて





APIからのJSONをオブジェクトに、できれば不変の値に変換する必要がある場合があります。Dartでは可能ですが、オブジェクトごとに多くのコーディングが必要です。幸いなことに、これをすべて行うのに役立つパッケージがあります。この記事では、この方法について説明します。



私たちの目標:



1。シリアル化



final user = User.fromJson({"name": "Maks"});
final json = user.toJson();


2.値として使用



final user1 = User.fromJson({"name": "Maks"});
final user2 = User((b) => b..name='Maks');
if (user1 == user2) print('    ');


3.不変性



user.name = 'Alex'; // 
final newUser = user.rebuild((b) => b..name='Alex'); // 




パッケージをインストールする



開きpubspec.yamlのファイルを、当社のフラッタプロジェクトに追加し、built_valueのパッケージをの依存関係



  ...
  built_value: ^7.1.0


そしてまた、追加built_value_generatorbuild_runnerパッケージdev_dependenciesこれらのパッケージは、必要なコードを生成するのに役立ちます。



dev_dependencies



 ...
  build_runner: ^1.10.2
  built_value_generator: ^7.1.0


pubspec.yaml ファイル保存し、flutter pub get」を実行して、必要なすべてのパッケージを取得します。



built_valueを作成します



これがどのように機能するかを確認するために、簡単なクラスを作成してみましょう。



新しいファイルuser.dartを作成します



import 'package:built_value/built_value.dart';

part 'user.g.dart';

abstract class User implements Built<User, UserBuilder> {
  String get name;

  User._();
  factory User([void Function(UserBuilder) updates]) = _$User;
}


そのため、1つの名前フィールドを持つ単純な抽象Userクラスを作成しました。これは、クラスがuser.g.dartの一部であり、UserBuilderを含むメインの実装がそこにあることを示しています。このファイルを自動的に作成するには、コマンドラインでこれを実行する必要があります。



flutter packages pub run build_runner watch


または



flutter packages pub run build_runner build


クラスで何かが変わるたびに再起動しないようにウォッチから始めます。



その後、新しいuser.g.dartファイルが表示されたことがわかりますこのプロセスを自動化することで、内部の内容と節約できる時間を確認できます。フィールドとシリアル化を追加すると、このファイルはさらに大きくなります。



私たちが得たものを確認しましょう:



final user = User((b) => b..name = "Max");
print(user);
print(user == User((b) => b..name = "Max")); // true
print(user == User((b) => b..name = "Alex")); // false


null可能



Userクラスに 新しいフィールド追加ます



abstract class User implements Built<User, UserBuilder> {
  String get name;
  String get surname;
...
}


あなたがこのようにしようとすると:



final user = User((b) => b..name = 'Max');


次に、エラーが発生します。



Tried to construct class "User" with null field "surname".


するに作るオプション、使用null可能



@nullable
String get surname;


または、毎回を付ける必要があります



final user = User((b) => b
  ..name = 'Max'
  ..surname = 'Madov');
print(user);


構築されたコレクション



配列を使ってみましょう。BuiltListはこれに役立ちます



import 'package:built_collection/built_collection.dart';
...
abstract class User implements Built<User, UserBuilder> {
  ...
  @nullable
  BuiltList<String> get rights;
...


final user = User((b) => b
  ..name = 'Max'
  ..rights.addAll(['read', 'write']));
print(user);


列挙



' read '、 ' write '、および ' delete '以外の値をとらないように権限を制限する必要があります。これを行うには、right.dartという名前の新しいファイルを作成します。新しいEnumClassを作成します



import 'package:built_collection/built_collection.dart';
import 'package:built_value/built_value.dart';

part 'right.g.dart';

class Right extends EnumClass {
  static const Right read = _$read;
  static const Right write = _$write;
  static const Right delete = _$delete;

  const Right._(String name) : super(name);

  static BuiltSet<Right> get values => _$rightValues;
  static Right valueOf(String name) => _$rightValueOf(name);
}


ユーザー:



@nullable
BuiltList<Right> get rights;


現在、権利権利タイプのみを受け入れます



final user = User((b) => b
  ..name = 'Max'
  ..rights.addAll([Right.read, Right.write]));
print(user);


シリアル化



これらのオブジェクトを簡単にJSONに変換したり元に戻したりできるように、クラスにさらにいくつかのメソッドを追加する必要があります。



...
import 'package:built_value/serializer.dart';
import 'serializers.dart';
...
abstract class User implements Built<User, UserBuilder> {
...
  Map<String, dynamic> toJson() => serializers.serializeWith(User.serializer, this);
  static User fromJson(Map<String, dynamic> json) =>
serializers.deserializeWith(User.serializer, json);

  static Serializer<User> get serializer => _$userSerializer;
}


原則として、これはシリアル化には十分です。



static Serializer<User> get serializer => _$userSerializer;


ただし、便宜上、toJsonメソッドfromJsonメソッドを追加しましょう



また、Rightクラスに1行追加します。



import 'package:built_value/serializer.dart';
,,,
class Right extends EnumClass {
...
  static Serializer<Right> get serializer => _$rightSerializer;
}


そして、serializers.dartという別のファイルを作成する必要があります



import 'package:built_collection/built_collection.dart';
import 'package:built_value/serializer.dart';
import 'package:built_value/standard_json_plugin.dart';
import 'package:built_value_demo/right.dart';
import 'package:built_value_demo/user.dart';

part 'serializers.g.dart';

@SerializersFor([Right, User])
final Serializers serializers =
(_$serializers.toBuilder()..addPlugin(StandardJsonPlugin())).build();


シリアル化が期待どおりに機能するためには、 新しいBuiltクラスをそれぞれ@SerializersFor([ ... ])に追加する必要があります



これで、取得したものを確認できます。



final user = User.fromJson({
  "name": "Max",
  "rights": ["read", "write"]
});
print(user);
print(user.toJson());


final user2 = User((b) => b
  ..name = 'Max'
  ..rights.addAll([Right.read, Right.write]));
print(user == user2); // true


値を変更しましょう:



final user3 = user.rebuild((b) => b
  ..surname = "Madov"
  ..rights.replace([Right.read]));
print(user3);


さらに



その結果、まだかなりたくさん書く必要があると言う人がいるでしょう。ただし、Visual Studioコードを使用する場合はBuilt Value Snippetsというスニペットをインストールすることをお勧めします。そうすればこれらすべてを自動的に生成できます。これを行うには、マーケットプレイスを検索するか、このリンクをたどってください



インストール後、Dartファイルに「bvと書き込むと、どのオプションが存在するかを確認できます。生成された「* .g.dart」ファイルをVisualStudio Codeに表示さ



せたくない場合は[設定]を開いて[ファイル] :[除外]を探し、[パターンの追加]をクリックして** / *。g.dart」。



次は何ですか?



一見、それほど努力する価値はないように思われるかもしれませんが、そのようなクラスがたくさんある場合、これはプロセス全体を大幅に促進し、スピードアップします。



PS私が提案した方法よりも実用的で効果的な方法を共有していただければ、とてもうれしく思います。



GitHubプロジェクト



パッケージ:

pub.dev/packages/built_value

pub.dev/packages/built_value_generator

pub.dev/packages/build_runner



All Articles