Às vezes, o JSON de uma API precisa ser convertido em um objeto e, de preferência, em um valor imutável. No Dart é possível, mas requer muita codificação para cada um dos objetos. Felizmente, existe um pacote que o ajudará a fazer tudo isso e, neste artigo, falarei sobre esse método.
Nosso objetivo:
1. Serialização
final user = User.fromJson({"name": "Maks"});
final json = user.toJson();
2. Use como valores
final user1 = User.fromJson({"name": "Maks"});
final user2 = User((b) => b..name='Maks');
if (user1 == user2) print(' ');
3. Imutabilidade
user.name = 'Alex'; //
final newUser = user.rebuild((b) => b..name='Alex'); //
Instale pacotes
Abra o arquivo pubspec.yaml em nosso projeto Flutter e adicione o pacote built_value às dependências :
...
built_value: ^7.1.0
E também adicionar os built_value_generator e pacotes build_runner para dev_dependencies . Esses pacotes irão ajudá-lo a gerar os códigos necessários.
dev_dependencies :
...
build_runner: ^1.10.2
built_value_generator: ^7.1.0
Salve o arquivo pubspec.yaml e execute “ flutter pub get ” para obter todos os pacotes necessários.
Criar valor_construído
Vamos criar uma classe simples para ver como isso funciona.
Crie um novo arquivo 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;
}
Então, criamos uma classe de usuário abstrata simples com um campo de nome , indicando que nossa classe faz parte de user.g.dart e a implementação principal está lá, incluindo UserBuilder . Para criar este arquivo automaticamente, você precisa executá-lo na linha de comando:
flutter packages pub run build_runner watch
ou
flutter packages pub run build_runner build
Começamos com o relógio para não reiniciar toda vez que algo muda na aula.
Depois disso, vemos que um novo arquivo user.g.dart apareceu . Você pode ver o que há dentro e quanto tempo vamos economizar automatizando esse processo. Quando adicionarmos mais campos e serialização, este arquivo ficará ainda maior.
Vamos verificar o que temos:
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
anulável
Adicione um novo campo de sobrenome à classe de usuário :
abstract class User implements Built<User, UserBuilder> {
String get name;
String get surname;
...
}
Se você tentar assim:
final user = User((b) => b..name = 'Max');
Então, obtemos um erro:
Tried to construct class "User" with null field "surname".
Para tornar o sobrenome opcional, useanulável:
@nullable
String get surname;
ou você precisa fornecer o sobrenome sempre :
final user = User((b) => b
..name = 'Max'
..surname = 'Madov');
print(user);
Coleção Construída
Vamos usar matrizes. BuiltList nos ajudará nisso :
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);
Enum
É necessário restringir os direitos de modo que não assuma nenhum outro valor além de ' ler ', ' escrever ' e ' excluir '. Para fazer isso, crie um novo arquivo chamado right.dart e crie uma nova 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);
}
Do utilizador:
@nullable
BuiltList<Right> get rights;
Agora, os direitos aceitam apenas o tipo certo :
final user = User((b) => b
..name = 'Max'
..rights.addAll([Right.read, Right.write]));
print(user);
Serialização
Para que esses objetos possam ser facilmente convertidos em JSON e vice-versa, precisamos adicionar mais alguns métodos às nossas classes:
...
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;
}
Em princípio, isso é suficiente para a serialização:
static Serializer<User> get serializer => _$userSerializer;
Mas, por conveniência, vamos adicionar os métodos toJson e fromJson .
Também adicionamos uma linha à classe certa:
import 'package:built_value/serializer.dart';
,,,
class Right extends EnumClass {
...
static Serializer<Right> get serializer => _$rightSerializer;
}
E você precisa criar outro arquivo chamado 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();
Cada nova classe Built precisa ser adicionada a @SerializersFor ([ ... ]) para que a serialização funcione conforme o esperado .
Agora podemos verificar o que temos:
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
Vamos mudar os valores:
final user3 = user.rebuild((b) => b
..surname = "Madov"
..rights.replace([Right.read]));
print(user3);
Além disso
Como resultado, haverá quem diga que ainda é preciso escrever muito. Mas se você usar o Visual Studio Code, recomendo instalar um snippet chamado Built Value Snippets e então você pode gerar tudo isso automaticamente. Para fazer isso, pesquise no Marketplace ou siga este link .
Após a instalação, escreva “ bv ” no arquivo Dart e você poderá ver quais opções existem.
Se você não quiser que o Visual Studio Code mostre os arquivos “ * .g.dart ” gerados , você precisa abrir Configurações e procurar Arquivos: Excluir , em seguida, clicar em Adicionar Padrão e adicionar “** / *. g.dart ”.
Qual é o próximo?
À primeira vista, pode parecer que tanto esforço não vale a pena, mas se você tiver muitas dessas aulas, isso vai facilitar e agilizar muito todo o processo.
PS Ficaria muito feliz e grato se você compartilhasse seus métodos, que considera mais práticos e eficazes do que o que propus. Pacotes de
projeto GitHub
:
pub.dev/packages/built_value
pub.dev/packages/built_value_generator
pub.dev/packages/build_runner