Conversão automática de Json usando json_serializable #1

pedromassango

Pedro Massango

Posted on February 21, 2020

Conversão automática de Json usando json_serializable #1

Depois de muito tempo, estou de volta na publicação de artigos, neste artigo vamos vou mostrar prar vocês como simplicar aquela tarefa chata que ninguém quer fazer, a redução de boilerplate quando estamos trabalhando com conversão de de uma classe Dart para json e vice-versa.

Todo desenvolvedor Flutter já se deparou com o problema de escrever as funções fromJson e toJson quanto estamos trabalhando com base de dados ou mesmo consumindo recursos de algum servidor. É um trabalho simples para projetos bem pequenos, mas quando vamos trabalhar com projetos grande chega a ser uma tarefa difícil de gerir a longo prazo.

Por este motivo websites como o Quicktype (um conversor de Json para classes de diferentes linguagens, incluindo Dart) se tornaram famosos e são ferramentas que estão sendo cada vez mais usadas no dia-a-dia dos desenvolvedores.

Eu vou mostrar para você um jeito mais simples de fazer isso usando um pacote Dart que gera as funções fromJson e toJson para você.

json_serializable

É um pacote da linguagem Dart que simplifica a conversão de uma classe Dart para json e vice-versa através da geração de código, continue lendo para ver o funcionamento dela.

Do contrário ao Quicktype este pacote evita ter classes conversoras de de objectos, já que todo trabalho sujo é transparente para o desenvolvedor em um arquivo separado.

Vamos dizer que temos a seguinte classe User em nosso projeto, e precisamos fazer com ele suporte conversão automática para json, tudo o que precisamos fazer é:

  • [x] Adicionar part 'user.g.dart'; (user, é o nome do ficheiro onde se encontra a classe)
  • [x] Anotar a classe com a anotação @JsonSerializable()
  • [x] Configurar a classe para usar as funcões gerada pelo pacote.

Com todos os passos feitos, teremos uma classe parecida com:

part of 'user.dart';

@JsonSerializable()
class User {
  final String firstName;
  final String lastName;
  final DateTime dateOfBirth;
  User({this.firstName, this.lastName, this.dateOfBirth});

  factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);

  Map<String, dynamic> toJson() => _$UserToJson(this);
}
Enter fullscreen mode Exit fullscreen mode

De momento a IDE poderá mostrar erros nas últimas linhas da classe, isso porque não geramos o codigo necessário para o funcionamento da classe. Após a execução de flutter pub run build_runner build teremos o problema resolvido e vai aparecer um novo ficheiro user.g.dart com o seguinte:

part of 'user.dart';

User_$UserFromJson(Map<String, dynamic> json) {
  return User(
    firstName: json['firstName'] as String,
    lastName: json['lastName'] as String,
    dateOfBirth: DateTime.parse(json['dateOfBirth'] as String),
  );
}

Map<String, dynamic> _$UserToJson(User instance) => <String, dynamic>{
      'firstName': instance.firstName,
      'lastName': instance.lastName,
      'dateOfBirth': instance.dateOfBirth.toIso8601String(),
    };
Enter fullscreen mode Exit fullscreen mode

Este é o arquivo que contém o código gerado, o codigo necessário para a conversão automática da sua classe para json. Não se preocupe, você não precisa saber da existência deste arquivo, e nem precisa usar ele.

Conversão de Classes usando outras classes como propiedades.

Por padrão este pacote não suporta conversão de propriedades de tipos desconhecidos, o que pode causar problema se você tiver uma classe do tipo:

@JsonSerializable()
class User {
  final Location location;
  User({this.location});

  factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);

  Map<String, dynamic> toJson() => _$UserToJson(this);
}
Enter fullscreen mode Exit fullscreen mode

O que o pacote vai fazer é tentar converter a instância de location para string, e uma vez que ela não é string irá disparar uma esceção de conversão.

Para resolver este problema, nós devemos fazer duas coisas: dizer ao pacote para que chame a função fromJson/toJson em objectos desconhecidos, e adicionar tais funções em nossos objectos.

  1. Setando a propiedade explicitToJson para true, o pacote vai então chamar fromJson/toJson sempre que precisar converter um tipo de dado desconhecido, neste caso quando ela precisar converter a propiedade location.
@JsonSerializable(explicitToJson: true)
class User {
  ...
}
Enter fullscreen mode Exit fullscreen mode
  1. Definir fromJson/toJson na classe que precisa de conversão.
part of 'location.dart';

@JsonSerializable()
class Location {
  final double lat;
  final double lgn;
  User({this.lat, this.lng});

  factory Location.fromJson(Map<String, dynamic> json) => _$LocationFromJson(json);

  Map<String, dynamic> toJson() => _$LocationToJson(this);
}
Enter fullscreen mode Exit fullscreen mode

E com isso a conversão automática agora funciona com objectos de tipos desconhecidos, ou seja com classes criadas por nós.

OBS: o pacote pode ser encontrado aqui.

Por hoje é tudo, segue para a parte dois, onde veremos conceitos mais avançados deste pacote.

💖 💪 🙅 🚩
pedromassango
Pedro Massango

Posted on February 21, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related