التسلسل إلى JSON وكائن غير قابل للتغيير. حول حزمة built_value لـ Flutter





في بعض الأحيان ، يلزم تحويل 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 في مشروع Flutter وأضف الحزمة built_value إلى التبعيات :



  ...
  built_value: ^7.1.0


وأيضا إضافة built_value_generator و build_runner حزم ل dev_dependencies . ستساعدك هذه الحزم في إنشاء الرموز المطلوبة.



تبعيات التنمية :



 ...
  build_runner: ^1.10.2
  built_value_generator: ^7.1.0


احفظ ملف pubspec.yaml وقم بتشغيل “ flutter pub get ” للحصول على جميع الحزم المطلوبة.



إنشاء build_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;
}


لذلك ، أنشأنا فئة مستخدم مجردة بسيطة مع حقل اسم واحد ، أشرنا إلى أن صنفنا جزء من 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


لاغية



أضف حقل اسم جديد إلى فئة المستخدم :



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".


ل جعل لقب اختياري، واستخداملاغية:



@nullable
String get surname;


أو تحتاج إلى إعطاء اللقب في كل مرة :



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


المجموعة المبنية



دعنا نستخدم المصفوفات. ستساعدنا BuildList على هذا :



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);


تعداد



من الضروري تقييد الحقوق بحيث لا تأخذ أي قيم أخرى غير " قراءة " و " كتابة " و " حذف ". للقيام بذلك ، قم بإنشاء ملف جديد باسم 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 .



نضيف أيضًا سطرًا واحدًا إلى الفئة الصحيحة:



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();


يجب إضافة كل فئة مدمجة جديدة إلى 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 Code ، فإنني أوصي بتثبيت مقتطف يسمى Built Value Snippets وبعد ذلك يمكنك إنشاء كل هذا تلقائيًا. للقيام بذلك ، ابحث في السوق أو اتبع هذا الرابط .



بعد التثبيت ، اكتب " bv " في ملف Dart ويمكنك معرفة الخيارات الموجودة.



إذا كنت لا تريد أن يعرض Visual Studio Code ملفات " * .g.dart " التي تم إنشاؤها ، فأنت بحاجة إلى فتح الإعدادات والبحث عن الملفات: استبعاد ، ثم النقر فوق إضافة نمط وإضافة "** / *. g.dart ”.



ماذا بعد؟



للوهلة الأولى ، قد يبدو أن هذا القدر من الجهد لا يستحق كل هذا العناء ، ولكن إذا كان لديك الكثير من هذه الفئات ، فسيؤدي ذلك إلى تسهيل وتسريع العملية برمتها.



ملاحظة: سأكون سعيدًا جدًا وممتنًا لك إذا قمت بمشاركة طرقك ، والتي تجدها أكثر عملية وفعالية من الطريقة التي اقترحتها. حزم



مشروع GitHub



:

pub.dev/packages/built_value

pub.dev/packages/built_value_generator

pub.dev/packages/build_runner



All Articles