Uma comparação de 6 ferramentas JsonToDart para desenvolvedores de Flutter/Dart

Tempo de leitura: 8 minutes

Em vez de escrever o código você mesmo, você sempre pode usar geradores para criar classes de modelos DART do JSON. Aqui estão os resultados da minha avaliação de algumas ferramentas gratuitas para você.

Para este teste, criei uma amostra de estrutura JSON com a qual todas as ferramentas precisam lidar. Você pode encontrá-lo abaixo:

{
    "string": "text",
    "number": 42,
    "bool": true,
    "array": [1,2,3],
    "object": {
        "string": "text",
        "number": 42,
        "bool": true,
        "array": [1,2,3]
    },
    "list": [{
        "string": "text",
        "number": 42,
        "bool": true,
        "array": [1,2,3]
    },
    {
        "string": "text",
        "number": 42,
        "bool": true,
        "array": [1,2,3]
    }]
}

Cada conversor receberá a mesma entrada e examinarei a saída criada. É executável? O nulo de segurança é suportado? O código é eficiente? Está faltando alguma coisa? Dê uma olhada nos resultados abaixo.

Comecei uma pesquisa na Internet e tomei os primeiros resultados que encontrei. A lista de participantes é

🔹 Quicktype
🔹 JSON to Dart Converter
🔹 JSON formatter
🔹 JSON to Dart Model
🔹 Dart QuickType
🔹 JSON to Dart online converter Null Safety

 

🔔 Vá com o Dart QuickType. Ele gera o melhor código Dart a partir de objetos JSON.

QuickType

O QuickType é um conversor multi-idioma para objetos JSON e também suporta o DART. Existem opções para personalizar a classe gerada. E também há uma extensão para o Visual Studio Code.

// To parse this JSON data, do
//
//     final myClass = myClassFromJson(jsonString);

import 'package:meta/meta.dart';
import 'dart:convert';

MyClass myClassFromJson(String str) => MyClass.fromJson(json.decode(str));

String myClassToJson(MyClass data) => json.encode(data.toJson());

class MyClass {
    MyClass({
        @required this.string,
        @required this.number,
        @required this.myClassBool,
        @required this.array,
        @required this.object,
        @required this.list,
    });

    final String string;
    final int number;
    final bool myClassBool;
    final List<int> array;
    final Object object;
    final List<Object> list;

    factory MyClass.fromJson(Map<String, dynamic> json) => MyClass(
        string: json["string"],
        number: json["number"],
        myClassBool: json["bool"],
        array: List<int>.from(json["array"].map((x) => x)),
        object: Object.fromJson(json["object"]),
        list: List<Object>.from(json["list"].map((x) => Object.fromJson(x))),
    );

    Map<String, dynamic> toJson() => {
        "string": string,
        "number": number,
        "bool": myClassBool,
        "array": List<dynamic>.from(array.map((x) => x)),
        "object": object.toJson(),
        "list": List<dynamic>.from(list.map((x) => x.toJson())),
    };
}

class Object {
    Object({
        @required this.string,
        @required this.number,
        @required this.objectBool,
        @required this.array,
    });

    final String string;
    final int number;
    final bool objectBool;
    final List<int> array;

    factory Object.fromJson(Map<String, dynamic> json) => Object(
        string: json["string"],
        number: json["number"],
        objectBool: json["bool"],
        array: List<int>.from(json["array"].map((x) => x)),
    );

    Map<String, dynamic> toJson() => {
        "string": string,
        "number": number,
        "bool": objectBool,
        "array": List<dynamic>.from(array.map((x) => x)),
    };
}

O resultado contém tudo, mas há problemas:

  • O QuickType não usa o required Keyword, mas a antiga anotação @required
  • O QuickType não suporta null-safety

Isso torna o código inutilizável sem alterações manuais. Também existem 77 questões abertas para o idioma DART e o código -fonte oficial não é atualizado há meses. Eu não esperaria nenhum progresso aqui, mas a ferramenta ainda economiza tempo de desenvolvimento, apesar das mudanças manuais necessárias.

Sólido, mas não perfeito. Mais rápido do que escrever sozinho. 😒

 

JSON to Dart Converter

O JSON to Dart Converter é um gerador de classes de modelos de Dart online gratuito. A única opção disponível é tornar os campos privados. Nesse caso, getters e setters são gerados.

class MyClass {
  String _string;
  int _number;
  bool _bool;
  Object<int> _array;
  Object _object;
  Object<List> _list;

  MyClass(
      {String string,
      int number,
      bool bool,
      Object<int> array,
      Object object,
      Object<List> list}) {
    this._string = string;
    this._number = number;
    this._bool = bool;
    this._array = array;
    this._object = object;
    this._list = list;
  }

  String get string => _string;
  set string(String string) => _string = string;
  int get number => _number;
  set number(int number) => _number = number;
  bool get bool => _bool;
  set bool(bool bool) => _bool = bool;
  Object<int> get array => _array;
  set array(Object<int> array) => _array = array;
  Object get object => _object;
  set object(Object object) => _object = object;
  Object<List> get list => _list;
  set list(Object<List> list) => _list = list;

  MyClass.fromJson(Map<String, dynamic> json) {
    _string = json['string'];
    _number = json['number'];
    _bool = json['bool'];
    _array = json['array'];
    _object =
        json['object'] != null ? new Object.fromJson(json['object']) : null;
    _list = json['list'] != null ? new List.fromJson(json['list']) : null;
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['string'] = this._string;
    data['number'] = this._number;
    data['bool'] = this._bool;
    data['array'] = this._array;
    if (this._object != null) {
      data['object'] = this._object.toJson();
    }
    if (this._list != null) {
      data['list'] = this._list.toJson();
    }
    return data;
  }
}

class Object {
  String _string;
  int _number;
  bool _bool;
  Object<int> _array;

  Object({String string, int number, bool bool, Object<int> array}) {
    this._string = string;
    this._number = number;
    this._bool = bool;
    this._array = array;
  }

  String get string => _string;
  set string(String string) => _string = string;
  int get number => _number;
  set number(int number) => _number = number;
  bool get bool => _bool;
  set bool(bool bool) => _bool = bool;
  Object<int> get array => _array;
  set array(Object<int> array) => _array = array;

  Object.fromJson(Map<String, dynamic> json) {
    _string = json['string'];
    _number = json['number'];
    _bool = json['bool'];
    _array = json['array'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['string'] = this._string;
    data['number'] = this._number;
    data['bool'] = this._bool;
    data['array'] = this._array;
    return data;
  }
}

O JSON pode ser convertido em uma aula de dardo, mas com grandes problemas:

  • Sem null-safety
  • Getters e setters são gerados para campos quando são privados
  • Array não foi reconhecido como List<int>, mas como object<int>
  • Lista de tipos object não foi reconhecida

No geral, o código é praticamente inútil, porque você precisará de tanto tempo corrigindo os erros que é mais rápido se escrevê -lo sozinho. Não há repositório do GitHub ou algo semelhante, apenas um endereço de email para contato. O site parece ter começado ontem e não há conteúdo, exceto este conversor.

Não use, é uma perda de tempo! ⛔

 

JSON formatter

O JSON Formatter é outro gerador de classes de modelo Dart online gratuito. Não há opções para selecionar, basta inserir o JSON e a ferramenta o converte em uma classe de Dart.

class Welcome2 {
    Welcome2({
        this.string,
        this.number,
        this.welcome2Bool,
        this.array,
        this.object,
        this.list,
    });

    String string;
    int number;
    bool welcome2Bool;
    List<int> array;
    Object object;
    List<Object> list;
}

class Object {
    Object({
        this.string,
        this.number,
        this.objectBool,
        this.array,
    });

    String string;
    int number;
    bool objectBool;
    List<int> array;
}

A saída é inútil, nem os métodos de Json e Tojson incluídos. Sem null-safety, sem campos finais, mas pelo menos a estrutura do objeto foi convertida corretamente.

Absolutamente não vale a pena! ⛔

 

JSON to Dart Model

O modelo JSON to DART fornece muitas opções de personalização para a saída. O código é de código aberto e atualmente existem três questões abertas. O projeto não parece ser conhecido como QuickType, mas o código gerado funcionará fora da caixa com a versão atual do DART.

///
/// Code generated by jsonToDartModel https://ashamp.github.io/jsonToDartModel/
///
class MyClassList {
/*
{
  "string": "text",
  "number": 42,
  "bool": true,
  "array": [
    1
  ]
} 
*/

  String? string;
  int? number;
  bool? theBool;
  List<int?>? array;

  MyClassList({
    this.string,
    this.number,
    this.theBool,
    this.array,
  });
  MyClassList.fromJson(Map<String, dynamic> json) {
    string = json['string']?.toString();
    number = json['number']?.toInt();
    theBool = json['bool'];
  if (json['array'] != null) {
  final v = json['array'];
  final arr0 = <int>[];
  v.forEach((v) {
  arr0.add(v.toInt());
  });
    array = arr0;
    }
  }
  Map<String, dynamic> toJson() {
    final data = <String, dynamic>{};
    data['string'] = string;
    data['number'] = number;
    data['bool'] = theBool;
    if (array != null) {
      final v = array;
      final arr0 = [];
  v!.forEach((v) {
  arr0.add(v);
  });
      data['array'] = arr0;
    }
    return data;
  }
}

class MyClassObject {
/*
{
  "string": "text",
  "number": 42,
  "bool": true,
  "array": [
    1
  ]
} 
*/

  String? string;
  int? number;
  bool? theBool;
  List<int?>? array;

  MyClassObject({
    this.string,
    this.number,
    this.theBool,
    this.array,
  });
  MyClassObject.fromJson(Map<String, dynamic> json) {
    string = json['string']?.toString();
    number = json['number']?.toInt();
    theBool = json['bool'];
  if (json['array'] != null) {
  final v = json['array'];
  final arr0 = <int>[];
  v.forEach((v) {
  arr0.add(v.toInt());
  });
    array = arr0;
    }
  }
  Map<String, dynamic> toJson() {
    final data = <String, dynamic>{};
    data['string'] = string;
    data['number'] = number;
    data['bool'] = theBool;
    if (array != null) {
      final v = array;
      final arr0 = [];
  v!.forEach((v) {
  arr0.add(v);
  });
      data['array'] = arr0;
    }
    return data;
  }
}

class MyClass {
/*
{
  "string": "text",
  "number": 42,
  "bool": true,
  "array": [
    1
  ],
  "object": {
    "string": "text",
    "number": 42,
    "bool": true,
    "array": [
      1
    ]
  },
  "list": [
    {
      "string": "text",
      "number": 42,
      "bool": true,
      "array": [
        1
      ]
    }
  ]
} 
*/

  String? string;
  int? number;
  bool? theBool;
  List<int?>? array;
  MyClassObject? object;
  List<MyClassList?>? list;

  MyClass({
    this.string,
    this.number,
    this.theBool,
    this.array,
    this.object,
    this.list,
  });
  MyClass.fromJson(Map<String, dynamic> json) {
    string = json['string']?.toString();
    number = json['number']?.toInt();
    theBool = json['bool'];
  if (json['array'] != null) {
  final v = json['array'];
  final arr0 = <int>[];
  v.forEach((v) {
  arr0.add(v.toInt());
  });
    array = arr0;
    }
    object = (json['object'] != null) ? MyClassObject.fromJson(json['object']) : null;
  if (json['list'] != null) {
  final v = json['list'];
  final arr0 = <MyClassList>[];
  v.forEach((v) {
  arr0.add(MyClassList.fromJson(v));
  });
    list = arr0;
    }
  }
  Map<String, dynamic> toJson() {
    final data = <String, dynamic>{};
    data['string'] = string;
    data['number'] = number;
    data['bool'] = theBool;
    if (array != null) {
      final v = array;
      final arr0 = [];
  v!.forEach((v) {
  arr0.add(v);
  });
      data['array'] = arr0;
    }
    if (object != null) {
      data['object'] = object!.toJson();
    }
    if (list != null) {
      final v = list;
      final arr0 = [];
  v!.forEach((v) {
  arr0.add(v!.toJson());
  });
      data['list'] = arr0;
    }
    return data;
  }
}

É um pouco irritante que os trechos JSON convertidos estejam incluídos no código como comentários. Além disso, a conversão de matrizes parece muito pesada. E, infelizmente, o conversor criou dois objetos idênticos com nomes diferentes. Mas, além disso, parece bom. No entanto, eu não usaria o resultado, pois o estilo de código é muito estranho e teria que fazer muita refatoração.

Trabalhando e utilizável, mas um estilo de código estranho. 🙄

 

Dart QuickType

O Dart QuickType é um fork de QuickType com uma base de código muito mais recente. Todas as falhas mencionadas do QuickType foram corrigidas aqui. Não há problemas abertos e o código do dart criado parece simples e pequeno.

class MyClass {
    MyClass({
        required this.string,
        required this.number,
        required this.myClassBool,
        required this.array,
        required this.object,
        required this.list,
    });

    final String string;
    final int number;
    final bool myClassBool;
    final List<int> array;
    final Object? object;
    final List<Object> list;

    factory MyClass.fromJson(Map<String, dynamic> json){ 
        return MyClass(
        string: json["string"] ?? "",
        number: json["number"] ?? 0,
        myClassBool: json["bool"] ?? false,
        array: json["array"] == null ? [] : List<int>.from(json["array"]!.map((x) => x)),
        object: json["object"] == null ? null : Object.fromJson(json["object"]),
        list: json["list"] == null ? [] : List<Object>.from(json["list"]!.map((x) => Object.fromJson(x))),
    );
    }

    Map<String, dynamic> toJson() => {
        "string": string,
        "number": number,
        "bool": myClassBool,
        "array": List<int>.from(array.map((x) => x)),
        "object": object?.toJson(),
        "list": List<Object>.from(list.map((x) => x?.toJson())),
    };
}

class Object {
    Object({
        required this.string,
        required this.number,
        required this.objectBool,
        required this.array,
    });

    final String string;
    final int number;
    final bool objectBool;
    final List<int> array;

    factory Object.fromJson(Map<String, dynamic> json){ 
        return Object(
        string: json["string"] ?? "",
        number: json["number"] ?? 0,
        objectBool: json["bool"] ?? false,
        array: json["array"] == null ? [] : List<int>.from(json["array"]!.map((x) => x)),
    );
    }

    Map<String, dynamic> toJson() => {
        "string": string,
        "number": number,
        "bool": objectBool,
        "array": List<int>.from(array.map((x) => x)),
    };
}

 

Valores padrão, null-safety, campos finais … tudo o que você precisa! A única coisinha que eu gostaria de acrescentar é equatable foi adicionado, porque eu a uso o tempo todo.

Vencedor claro, sem objeções, melhor geração de código! ✔

 

 

JSON to Dart online converter Null Safety

O Json to Dart Online Converter Null Safety não tem opções, exceto para definir o nome da classe e o código gerado não funciona fora da caixa.

class MyClass {
  MyClass({
    required this.string,
    required this.number,
    required this.bool,
    required this.array,
    required this.object,
    required this.list,
  });
  late final String string;
  late final int number;
  late final bool bool;
  late final List<int> array;
  late final Object object;
  late final List<List> list;
  
  MyClass.fromJson(Map<String, dynamic> json){
    string = json['string'];
    number = json['number'];
    bool = json['bool'];
    array = List.castFrom<dynamic, int>(json['array']);
    object = Object.fromJson(json['object']);
    list = List.from(json['list']).map((e)=>List.fromJson(e)).toList();
  }

  Map<String, dynamic> toJson() {
    final _data = <String, dynamic>{};
    _data['string'] = string;
    _data['number'] = number;
    _data['bool'] = bool;
    _data['array'] = array;
    _data['object'] = object.toJson();
    _data['list'] = list.map((e)=>e.toJson()).toList();
    return _data;
  }
}

class Object {
  Object({
    required this.string,
    required this.number,
    required this.bool,
    required this.array,
  });
  late final String string;
  late final int number;
  late final bool bool;
  late final List<int> array;
  
  Object.fromJson(Map<String, dynamic> json){
    string = json['string'];
    number = json['number'];
    bool = json['bool'];
    array = List.castFrom<dynamic, int>(json['array']);
  }

  Map<String, dynamic> toJson() {
    final _data = <String, dynamic>{};
    _data['string'] = string;
    _data['number'] = number;
    _data['bool'] = bool;
    _data['array'] = array;
    return _data;
  }
}

class List {
  List({
    required this.string,
    required this.number,
    required this.bool,
    required this.array,
  });
  late final String string;
  late final int number;
  late final bool bool;
  late final List<int> array;
  
  List.fromJson(Map<String, dynamic> json){
    string = json['string'];
    number = json['number'];
    bool = json['bool'];
    array = List.castFrom<dynamic, int>(json['array']);
  }

  Map<String, dynamic> toJson() {
    final _data = <String, dynamic>{};
    _data['string'] = string;
    _data['number'] = number;
    _data['bool'] = bool;
    _data['array'] = array;
    return _data;
  }
}

Algumas falhas com este código:

  • Palavra-chave late desnecessária ao usar necessária
  • Variáveis podem ser nomeadas como palavras-chave → erro do compilador
  • Cria duas classes idênticas objeto e listar
  • Nenhum valores de fallback no método de fromJson
  • Erros de compilador adicionais com classes criadas

Muitas correções manuais precisavam ser úteis. ⛔

 

Conclusão

O Dart QuickType gera o melhor código e é o vencedor desta comparação. Até certo ponto, você também pode usar o JSON to Dart Model se não se importar com o estilo de código. Todos os outros conversores não valem o tempo, então pule-os.

Eu perdi um bom conversor? Conte -me sobre isso se você acha que eu deveria tentar 😉