Freezed dan JSON Serialization
Selamat datang di Freezed
, pembuat code generator untuk data-classes/unions/pattern-matching/cloning
.
Package freezed
dan json_serializable
adalah salah satu package code generation.
Motivasiโ
Memang Dart itu keren, tapi mendefinisikan "model" bisa jadi merepotkan. Kita mungkin harus:
- Mendefinisikan constructor dan properties
- Meng-override method
toString
, operator==
, danhashCode
- Mengimplementasikan method
copyWith
untuk menduplikasi objek - Menangani de/serialization
Semua ini bisa membutuhkan ratusan baris kode, yang rentan terhadap kesalahan dan bisa sangat mengurangi keterbacaan model Anda.
Package Freezed
mencoba mengatasi masalah ini dengan mengimplementasikan sebagian besar hal tersebut untuk Anda, sehingga Anda bisa lebih fokus pada definisi model Anda.
Sebelumnya | Sesudahnya |
---|---|
Menjalankan Build Runnerโ
Dart (Rekomendasi gunakan ini)โ
Bisa digunakan di project flutter. Karena memang flutter itu dibuat menggunakan dart.
Sekali eksekusi:
dart run build_runner build --delete-conflicting-outputs
Selalu memantau perubahan file dan melakukan build ulang file generated *.freezed.dart
dan *.g.dart
. Mirip seperti hot reload.
dart run build_runner watch --delete-conflicting-outputs
Flutterโ
Sekali eksekusi:
flutter pub run build_runner build --delete-conflicting-outputs
Selalu memantau perubahan file dan melakukan build ulang file generated *.freezed.dart
dan *.g.dart
. Mirip seperti hot reload.
flutter pub run build_runner watch --delete-conflicting-outputs
Pemasangan (Install)โ
Untuk menggunakan Freezed
, Anda memerlukan pengaturan build_runner/code-generator
yang umum.
Pertama, install build_runner
dan Freezed
dengan menambahkannya ke file pubspec.yaml
Anda:
Pasang Semua Packageโ
Gak mau ribet pakai ini.
flutter pub add freezed_annotation json_annotation dev:build_runner dev:freezed dev:json_serializable
Pasang Satu Persatuโ
Ada package yang sudah terpasang pakai ini.
flutter pub add --dev build_runner
flutter pub add freezed_annotation dev:freezed
Jika menggunakan freezed
untuk generate method fromJson/toJson
, silahkan tambahkan:
flutter pub add json_annotation dev:json_serializable
pubspec.yaml
โ
name: kaesa_app
description: A new Flutter project.
publish_to: 'none'
version: 1.0.0+1
environment:
sdk: '>=2.17.6 <3.0.0'
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.2
# code generator (jangan salah peletakan depedencies)
freezed_annotation: ^2.4.1
json_annotation: ^4.8.1
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^3.0.1
# code generator (jangan salah peletakan depedencies)
# dart run build_runner build --delete-conflicting-outputs
build_runner: ^2.4.8
freezed: ^2.4.7
json_serializable: ^6.7.1
flutter:
uses-material-design: true
Mengistal ini akan menambahkan tiga package:
build_runner
: perangkat untuk menjalankan code-generatorfreezed
: pembuat kode (code generator)freezed_annotation
: package yang berisi anotasi untukยfreezed
โ Warning invlid_annotation_target
โ
Disabling invalid_annotation_target
warning and warning in generates files.
Mematikan peringatan invalid_annotation_target
dan peringatan di file yang dibuat oleh freezed
.
Jika Anda berencana menggunakan freezed
bersama dengan json_serializable
, versi terbaru dari json_serializable
dan meta
mungkin mengharuskan Anda untuk menonaktifkan peringatan invalid_annotation_target
.
Untuk melakukannya, Anda dapat menambahkan yang berikut ini ke file analysis_options.yaml
di root project Anda:
The annotation JsonSerializable
can only be used on classes.
The annotation JsonKey
can only be used on fields or getters.
Jika Anda mendapatkan warning di atas, silahkan tambahkan aturan (rules) untuk static analyzer pada file analysis_options.yaml
.
analysis_options.yaml
โ
include: package:flutter_lints/flutter.yaml
# info lengkap: https://github.com/rrousselGit/freezed/issues/488
analyzer:
exclude:
- '**/*.g.dart'
- '**/*.freezed.dart'
errors:
invalid_annotation_target: ignore
linter:
rules:
.gitignore
โ
# build_runner generated files from code generator
*.freezed.dart
*.g.dart
Menjalankan Generatorโ
Untuk menjalankan generator kode, jalankan perintah berikut:
dart run build_runner build
Catatan: Seperti kebanyakan generator kode, freezed
akan membutuhkan Anda untuk both import anotasi (freezed_annotation
) dan menggunakan kata kunci part
di bagian atas file Anda.
Oleh karena itu, file yang ingin menggunakan Freezed
akan dimulai dengan:
import 'package:freezed_annotation/freezed_annotation.dart';
part 'my_file.freezed.dart';
PERTIMBANGKAN untuk juga mengimpor package:flutter/foundation.dart
. Alasannya, mengimpor foundation.dart
juga mengimpor kelas-kelas untuk membuat objek terbaca dengan baik di devtool Flutter. Jika Anda mengimpor foundation.dart
, Freezed
akan melakukannya secara otomatis untuk Anda.
Membuat Model menggunakan Freezedโ
Lebih baik contoh daripada penjelasan abstrak yang panjang, jadi inilah contoh kelas Freezed yang umum:
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:flutter/foundation.dart'; // for devtools
// wajib: mengaitkan "person_model.dart" kita dengan kode yang dihasilkan oleh Freezed
part 'person_model.freezed.dart';
// opsional: Karena class Person bersifat serializable, kita harus menambahkan baris ini.
// Tetapi jika Person tidak serializable, kita bisa melewatkannya.
part 'person_model.g.dart';
class Person with _$Person {
const factory Person({
required String firstName,
required String lastName,
required int age,
}) = _Person;
factory Person.fromJson(Map<String, Object?> json)
=> _$PersonFromJson(json);
}
Potongan kode berikut mendefinisikan model bernama Person
:
Person
memiliki 3 properti:firstName
,lastName
, danage
- Karena kita menggunakan
@freezed
, semua properti kelas ini bersifat immutable (tidak dapat diubah). - Karena kita mendefinisikan
fromJson
, kelas ini bersifat de/serializable (dapat diubah menjadi JSON dan sebaliknya). Freezed akan menambahkan metodetoJson
untuk kita. - Freezed juga akan secara otomatis menghasilkan:
- method
copyWith
, untuk menduplikasi objek dengan properti yang berbeda - override
toString
yang mencantumkan semua properti objek - override
operator ==
danhashCode
(karenaPerson
bersifat immutable)
- method
Dari contoh ini, kita dapat melihat beberapa hal:
- Diperlukan untuk menganotasi model kita dengan
@freezed
(atau@freezed
/@unfreezed
, lebih lanjut tentang itu nanti). Anotasi ini memberi tahu Freezed untuk menghasilkan kode untuk kelas itu. - Kita juga harus menerapkan mixin dengan nama kelas kita, diawali dengan
_$
. Mixin ini yang mendefinisikan berbagai properties/methods objek kita. - Saat mendefinisikan constructor dalam kelas Freezed, kita harus menggunakan kata kunci
factory
seperti yang ditunjukkan (const
opsional).
Parameter constructor ini akan menjadi daftar semua properti yang dimiliki kelas ini.
Parameter tidak harus diberi nama dan wajib diisi (required
). Jangan ragu untuk menggunakan parameter opsional posisi jika Anda mau!
Mendefinisikan Kelas Mutable (bisa diubah) sebagai Pengganti Kelas Immutableโ
Sejauh ini, kita telah melihat bagaimana cara mendefinisikan model di mana semua propertinya bersifat final
(tidak bisa diubah); tetapi Anda mungkin ingin mendefinisikan properti yang bisa diubah dalam model Anda.
Freezed mendukung ini, dengan mengganti anotasi @freezed
dengan @unfreezed
:
class Person with _$Person {
factory Person({
required String firstName,
required String lastName,
required final int age,
}) = _Person;
factory Person.fromJson(Map<String, Object?> json)
=> _$PersonFromJson(json);
}
Ini mendefinisikan model yang sebagian besar identik dengan cuplikan kode kita sebelumnya, tetapi dengan perbedaan berikut:
firstName
danlastName
sekarang bisa diubah. Oleh karena itu, kita dapat menulis:
void main() {
var person = Person(firstName: 'John', lastName: 'Smith', age: 42);
person.firstName = 'Mona';
person.lastName = 'Lisa';
}
age
masih tidak bisa diubah, karena kita secara eksplisit menandai properti tersebut sebagaifinal
.Person
tidak lagi memiliki implementasi==/hashCode
khusus:
void main() {
var john = Person(firstName: 'John', lastName: 'Smith', age: 42);
var john2 = Person(firstName: 'John', lastName: 'Smith', age: 42);
print(john == john2); // false
}
- Tentu saja, karena kelas
Person
kita bisa diubah, maka tidak mungkin lagi untuk membuat instance-nya menggunakanconst
.
Mengizinkan Mutasi List/Map/Setโ
Secara default, ketika menggunakan @freezed
(tetapi tidak @unfreezed
), properti dengan tipe List
/Map
/Set
diubah menjadi immutable (tidak dapat diubah).
Ini berarti bahwa menulis kode berikut akan menyebabkan exception runtime:
class Example with _$Example {
factory Example(List<int> list) = _Example;
}
void main() {
var example = Example([]);
example.list.add(42); // akan menghasilkan exception karena kita mencoba mengubah collection
}
Perilaku ini dapat dinonaktifkan dengan menulis:
(makeCollectionsUnmodifiable: false)
class Example with _$Example {
factory Example(List<int> list) = _Example;
}
void main() {
var example = Example([]);
example.list.add(42); // Tidak akan eror
}
Bagaimana copyWith
Bekerjaโ
Seperti yang dijelaskan sebelumnya, ketika kita mendefinisikan sebuah model menggunakan Freezed, maka code-generator akan secara otomatis menghasilkan metode copyWith
untuk kita. Metode ini digunakan untuk mengkloning sebuah objek dengan nilai yang berbeda.
Misalnya jika kita mendefinisikan:
class Person with _$Person {
factory Person(String name, int? age) = _Person;
}
Maka kita bisa menulis:
void main() {
var person = Person('Remi', 24);
// `age` tidak diberikan, nilainya masih sama
print(person.copyWith(name: 'Dash')); // Person(name: Dash, age: 24)
// `age` diatur menjadi `null`
print(person.copyWith(age: null)); // Person(name: Remi, age: null)
}
Perhatikan bahwa Freezed mendukung person.copyWith(age: null)
.