В Dart существует множество пакетов для JSON сериализации/десериализации, однако практически все они завязаны на генерации кода. Связанно это с AOT компиляцией и тем что библиотека для рефлексии в Dart (dart:mirros) работает только с JIT компиляцией, следовательно она не доступна в Flutter.
Этот пакет построен на библиотеке dart:mirros, не использует генерацию кода и пригодится тем кто использует Dart вне Flutter-а, и работает с JSON.
Это JSON сериализатор/десериализатор для Dart основанный на библиотеке dart:mirrors. Так же как и dart:mirros работает только с JIT компиляцией, в Flutter-е не работает.
Предоставляет функционал:
- сериализацию и десериализацию объектов классов;
- поддерживает nullable значения;
- поддерживает list, map;
- при помощи аннотаций в коде можно изменить имя поля в JSON, игнорировать ненужные поля, указать конструктор который будет использоваться при десериализации.
Добавьте Emerald в ваш pubspec.yaml файл:
dependencies:
emerald: ^1.1.1
Импортируйте ossa в файле где он должен использоваться:
import 'package:emerald/emerald.dart';
Для сериализации объектов в JSON строку в Emerald используется метод serialize класса Emerald.
Сериализуются все публичные, не статические поля класса.
Пример сериализации объекта в JSON строку:
class User {
final String name;
final int age;
User(this.name, this.age);
}
void main() {
// Creates instance of your object
var object = User('Alex', 21);
// Serializes instance to json string
var json = Emerald.serialize(object);
print(json);
}
Ожидаемый вывод:
{"name":"Alex","age":21}
Для десериализации JSON строки в объект, в Emerald используется метод deserialize<T> класса Emerald, где T - тип объекта который мы желаем получить.
В момент создания экземпляра класса Emerald выбирает конструктор класса, которым он воспользуется для создания. По умолчанию он выбирает конструктор по умолчанию, однако при помощи аннотаций можно задать конструктор для Emerald - об этом написанно здесь.
После выбора конструктора, в случае если конструктор содержит параметры (как именованные, так и обычные), Emerald пытается подставить в параметры конструктора значения из JSON строки. Имена из JSON сапоставляются с именами параметров конструктора. При помощи аннотаций можно задать для параметра конструктора имена для сапоставления их с JSON полями - об этом написанно здесь.
После создания экземпляра класса, Emerald пытается присвоить значения всем полям класса, которые не являются final или статическими. Имена полей сапоставляются с именами из JSON. При помощи аннотаций можно задать имена для полей класса, которые будут сапоставляться с JSON именами - об этом написанно здесь.
Пример десериализации JSON строки в объект:
class User {
final String name;
final int age;
User(this.name, this.age);
@override
String toString() {
return 'User with name: $name, age: $age.';
}
}
void main() {
var json = '{"name": "Alex", "age": 21}';
// Deserializes json string to instance of class
var object = Emerald.deserialize<User>(json);
print(object);
}
Ожидаемый вывод:
User with name: Alex, age: 21.
Emerald при десериализации JSON строки в объект выбирает конструктор класса, которым он воспользуется.
По умолчанию он выбирает конструктор по умолчанию (не именованный и не фабричный). Однако конструктор для Emerald можно указать при помощи аннотации @jsonConstructor.
Пример использования отдельного конструктора для JSON десериализации:
class User {
final String name;
final int age;
final List<User> friends;
User(this.name, this.age, [this.friends = const []]);
// Use json constructor annotation for set this constructor as constructor for Emerald
@jsonConstructor
User.json({required this.name, required this.age, required this.friends});
bool isEqual(User other) {
if (name != other.name) {
return false;
}
if (age != other.age) {
return false;
}
if (friends.length != other.friends.length) {
return false;
}
for (var i = 0; i < friends.length; i++) {
if (!friends[i].isEqual(other.friends[i])) {
return false;
}
}
return true;
}
}
void main() {
// Creates instance of your object
var object = User('Alex', 21, [User('Bill', 22)]);
// Serializes it to json string
var json = Emerald.serialize(object);
print(json);
// Deserializes json string to instance of Gamer
var deserialized = Emerald.deserialize<User>(json);
// Checks is initial object and deserialized object equal
var isEqual = object.isEqual(deserialized);
print(isEqual);
}
Ожидаемый вывод:
{"name":"Alex","age":21,"friends":[{"name":"Bill","age":22,"friends":[]}]}
true
При помощи аннотиации @JsonProperty вы можете пометить поле, которые должен игнорировать Emerald при сериализации.
Пример использования аннотаций для игнорирования полей при сериализации:
class User {
final String name;
final int age;
// Use json property annotation for ignore this field
@JsonProperty(ignore: true)
final int someCalculateField;
User(this.name, this.age) : someCalculateField = age * 2;
}
void main() {
// Creates object
var object = User('Alex', 21);
// Serializes it to json string
var json = Emerald.serialize(object);
print(json);
}
Ожидаемый вывод:
{"name":"Alex","age":21}
Emerald при сериализации полей класса берет имена полей в качестве имен для JSON. Однако вы можете при помощи аннотаций @JsonProperty указать имена для JSON полей при сериализации.
Пример указания имен JSON полей для сериализации:
class User {
// Use json property annotation for set custom json name for this field
@JsonProperty(name: 'custom_name')
final String name;
// Use json property annotation for set custom json name for this field
@JsonProperty(name: 'custom_age')
final int age;
// Use json parameter annotation for set custom json name for parameters
User(this.name, this.age);
bool isEqual(User other) {
return name == other.name && age == other.age;
}
}
void main() {
var object = User('Alex', 21);
var json = Emerald.serialize(object);
print(json);
}
Ожидаемый вывод:
{"custom_name":"Alex","custom_age":21}
Однако, что делать с конструктором класса, ведь Emerald при десериализации сапостовляет имена параметров конструктора с JSON полями.
Для этого в Emerald существует аннотация @JsonParameter, при помощи которой вы можете задать имя параметра, которое будет сапоставлятся с именами JSON полей.
Пример указания имен для JSON полей для сериализации, а так же указания имен для параметров конструктора:
class User {
// Use json property annotation for set custom json name for this field
@JsonProperty(name: 'custom_name')
final String name;
// Use json property annotation for set custom json name for this field
@JsonProperty(name: 'custom_age')
final int age;
// Use json parameter annotation for set custom json name for parameters
User(@JsonParameter(name: 'custom_name') this.name,
@JsonParameter(name: 'custom_age') this.age);
bool isEqual(User other) {
return name == other.name && age == other.age;
}
}
void main() {
// Creates instance of your object
var object = User('Alex', 21);
// Serializes it to json string
var json = Emerald.serialize(object);
print(json);
// Deserializes json string to instance of class
var deserialized = Emerald.deserialize<User>(json);
// Checks is initial object and deserialized object equal
var isEqual = object.isEqual(deserialized);
print(isEqual);
}
Ожидаемый вывод:
{"custom_name":"Alex","custom_age":21}
true
Для форматирования DateTime при сериализации и десериализации в Emerald есть аннотация @JsonDateFormat. При помощи неё можно задать шаблон конвертации даты, используются шаблоны доступные в пакете intl.
Пример использования аннотации @JsonDateFormat для форматирования даты при сериализации:
class Report {
// Create pattern for date time serialize and deserialize
static const jsonDateFormat = JsonDateFormat(pattern: 'yMd');
final String title;
// Set date time format annotation to field
@jsonDateFormat
DateTime date;
// Set date time format annotation to constructor property
Report(this.title, @jsonDateFormat this.date);
}
void main() {
var object = Report('Old report', DateTime.now());
// Serializes instance of User to json string
var json = Emerald.serialize(object);
print(json);
// Deserializes json string to instance of class
var deserialized = Emerald.deserialize<Report>(json);
print(deserialized.date);
}
Возможный вывод:
{"title":"Old report","date":"6/16/2022"}
2022-06-16 00:00:00.000