JSON in Dart

Genera classi Dart da JSON con fromJson e toJson

Prova un esempio
Nome classe radice:

Input JSON

Output Dart

Esegue in locale · Sicuro per incollare segreti
Le classi Dart appariranno qui…

Cos'è la conversione da JSON a Dart?

La conversione da JSON a Dart prende un oggetto JSON grezzo e produce definizioni di classi Dart con campi tipizzati, un costruttore con parametri nominati, una factory fromJson e un metodo toJson. Dart non dispone di reflection a runtime in Flutter (dart:mirrors è disabilitato), quindi non è possibile deserializzare JSON in oggetti tipizzati senza scrivere codice di mappatura esplicito. Ogni risposta di API REST, documento Firebase o payload di configurazione richiede una classe modello Dart corrispondente prima di poter accedere ai suoi campi con la sicurezza dei tipi.

Una tipica classe modello Dart per JSON dichiara campi final per ogni chiave, un costruttore con parametri nominati (usando la parola chiave required per i campi non nullable), una factory constructor chiamata fromJson che legge da una Map di String a dynamic, e un metodo toJson che restituisce una Map di String a dynamic. Gli oggetti JSON annidati diventano classi separate. Gli array diventano campi List tipizzati. I valori JSON nullable usano la sintassi null-safety di Dart con il suffisso ? sul tipo.

Scrivere queste classi modello a mano significa leggere ogni chiave JSON, decidere il tipo Dart, creare il cast fromJson per ogni campo (inclusa la mappatura delle liste con .map().toList()), costruire il map literal toJson e ripetere il processo per ogni oggetto annidato. Per un oggetto JSON con 12 campi e 2 oggetti annidati, ciò significa 3 classi, 6 righe di factory e decine di espressioni di cast. Un convertitore produce tutto questo in pochi millisecondi da un singolo incolla.

Perché usare un convertitore da JSON a Dart?

Scrivere manualmente classi modello Dart da JSON implica leggere i nomi dei campi, dedurre i tipi dai valori di esempio, scrivere i cast fromJson con la corretta gestione dei null e ripetere il processo per gli oggetti annidati. Quando la struttura dell'API cambia, ogni aggiornamento di campo tocca il costruttore, fromJson e toJson. Un convertitore elimina questo lavoro ripetitivo.

Generazione immediata di classi
Incolla il JSON e ottieni classi Dart complete con costruttori, factory fromJson e metodi toJson in meno di un secondo. Oggetti annidati e liste vengono rilevati e mappati automaticamente.
🔒
Elaborazione orientata alla privacy
La conversione avviene interamente nel browser tramite JavaScript. I tuoi dati JSON non lasciano mai il tuo computer. Chiavi API, token e payload di produzione rimangono privati.
📝
Output null-safe
Le classi generate usano la null safety garantita di Dart. I campi JSON nullable ottengono il suffisso ? sul tipo e omettono la parola chiave required nei costruttori. I campi non nullable sono marcati required.
📦
Nessuna installazione né registrazione
Apri la pagina e incolla il tuo JSON. Non è necessario il Dart SDK, nessuna dipendenza pub, nessun account. Funziona su qualsiasi dispositivo con un browser.

Casi d'uso di JSON in Dart

Sviluppo di app Flutter
Genera classi modello per le risposte di API REST consumate dai pacchetti http o dio. Incolla il JSON restituito dal tuo backend e ottieni classi Dart pronte per jsonDecode e il rendering dei widget.
Integrazione con Firebase / Firestore
Crea classi modello tipizzate per i snapshot di documenti Firestore. Incolla un documento di esempio come JSON, genera la classe Dart e usa fromJson con snapshot.data() nel tuo layer repository.
Modelli per la gestione dello stato
Definisci oggetti di stato tipizzati per Riverpod, Bloc o Provider. Incolla la forma di stato attesa come JSON e ottieni classi Dart immutabili con toJson per la persistenza e l'idratazione dello stato.
Generazione di codice per client API
Produci modelli di richiesta e risposta per client API Retrofit o Chopper. Incolla payload JSON di esempio e ottieni classi Dart che corrispondono agli schemi di risposta OpenAPI.
Testing automatizzato
Crea fixture di test tipizzate da risposte API reali. Incolla un campione JSON, genera la classe modello e usala direttamente nei test unitari e di widget senza scrivere manualmente le struct di fixture.
Imparare i pattern Dart
Gli studenti che imparano Flutter possono incollare qualsiasi struttura JSON e vedere come Dart la rappresenta: campi final, costruttori nominati, pattern factory fromJson e annotazioni null-safety nella pratica.

Mappatura dei tipi da JSON a Dart

Ogni valore JSON si mappa a un tipo Dart specifico. La tabella seguente mostra come il convertitore traduce ogni tipo JSON. La colonna Alternativa mostra i tipi usati in scenari di mappatura meno comuni o manuali.

Tipo JSONEsempioTipo DartAlternativa
string"hello"StringString
number (integer)42intint
number (float)3.14doubledouble
booleantrueboolbool
nullnulldynamicNull / dynamic
object{"k": "v"}NestedClassMap<String, dynamic>
array of strings["a", "b"]List<String>List<String>
array of objects[{"id": 1}]List<Item>List<Item>
mixed array[1, "a"]List<dynamic>List<dynamic>

Approcci alla serializzazione JSON in Dart

Dart e Flutter offrono diversi modi per gestire la serializzazione JSON. Il metodo manuale fromJson/toJson è l'approccio più semplice e non richiede generazione di codice. Per progetti di maggiori dimensioni, le soluzioni basate su build_runner come json_serializable e freezed generano il codice ripetitivo in fase di compilazione, riducendo gli errori e mantenendo i modelli coerenti con il contratto JSON.

ApproccioDescrizioneSorgente
json_serializableCode-generation-based JSON serialization. Generates .g.dart files at build time via build_runner. Type-safe and compile-time verified.Official (Google)
freezedGenerates immutable data classes with copyWith, fromJson/toJson, equality, and pattern matching support. Built on top of json_serializable.Community (rrousselGit)
built_valueGenerates immutable value types with serialization. Enforces immutability patterns. Used in larger codebases with strict data modeling.Google
dart_mappableAnnotation-based mapper that generates fromJson, toJson, copyWith, and equality. Simpler setup than freezed with similar features.Community
Manual fromJson/toJsonHand-written factory constructors and toJson methods. No code generation needed. Full control over the mapping logic.Built-in Dart

Manuale vs json_serializable vs freezed

Dart offre tre approcci comuni per le classi modello JSON. Il metodo manuale fromJson/toJson non ha dipendenze. json_serializable automatizza il codice di mappatura. freezed aggiunge immutabilità, copyWith e pattern matching sopra json_serializable.

Manual fromJson/toJson
Scrivi factory fromJson e metodi toJson a mano. Nessuna dipendenza, nessun passaggio build_runner. Hai il pieno controllo sulla logica di cast e sulla gestione degli errori. Indicato per progetti piccoli con pochi modelli, o quando serve una deserializzazione personalizzata che i generatori di codice non riescono a esprimere. Questo è il formato di output generato da questo strumento.
json_serializable
Annota la tua classe con @JsonSerializable() ed esegui dart run build_runner build. Il generatore crea un file .g.dart con le funzioni _$ClassFromJson e _$ClassToJson. Gestisce @JsonKey per la rinominazione dei campi, i valori predefiniti e i convertitori personalizzati. La scelta standard per progetti Flutter di medie e grandi dimensioni.
freezed
Annota con @freezed e ottieni classi immutabili con fromJson, toJson, copyWith, uguaglianza (== e hashCode) e toString generati automaticamente. Supporta i tipi union per i pattern sealed class. Richiede sia freezed che json_serializable come dipendenze di sviluppo. Ideale per modelli di gestione dello stato e oggetti di dominio complessi.

Esempi di codice

Questi esempi mostrano come usare le classi Dart generate per la deserializzazione JSON, come configurare json_serializable con build_runner e come generare classi Dart programmaticamente da JavaScript e Python.

Dart (manual fromJson / toJson)
import 'dart:convert';

class User {
  final int id;
  final String name;
  final String email;
  final bool active;
  final Address address;
  final List<String> tags;

  User({
    required this.id,
    required this.name,
    required this.email,
    required this.active,
    required this.address,
    required this.tags,
  });

  factory User.fromJson(Map<String, dynamic> json) => User(
    id: json['id'] as int,
    name: json['name'] as String,
    email: json['email'] as String,
    active: json['active'] as bool,
    address: Address.fromJson(json['address'] as Map<String, dynamic>),
    tags: (json['tags'] as List<dynamic>).map((e) => e as String).toList(),
  );

  Map<String, dynamic> toJson() => {
    'id': id,
    'name': name,
    'email': email,
    'active': active,
    'address': address.toJson(),
    'tags': tags,
  };
}

class Address {
  final String street;
  final String city;
  final String zip;

  Address({required this.street, required this.city, required this.zip});

  factory Address.fromJson(Map<String, dynamic> json) => Address(
    street: json['street'] as String,
    city: json['city'] as String,
    zip: json['zip'] as String,
  );

  Map<String, dynamic> toJson() => {'street': street, 'city': city, 'zip': zip};
}

void main() {
  final jsonStr = '{"id":1,"name":"Alice","email":"alice@example.com","active":true,"address":{"street":"123 Main","city":"Springfield","zip":"12345"},"tags":["admin","user"]}';
  final user = User.fromJson(jsonDecode(jsonStr));
  print(user.name); // -> Alice
  print(jsonEncode(user.toJson())); // -> round-trip back to JSON
}
Dart (json_serializable + build_runner)
// pubspec.yaml dependencies:
//   json_annotation: ^4.8.0
//   dev_dependencies:
//     build_runner: ^2.4.0
//     json_serializable: ^6.7.0

import 'package:json_annotation/json_annotation.dart';
part 'user.g.dart'; // generated by: dart run build_runner build

@JsonSerializable()
class User {
  final int id;
  final String name;
  final String email;
  @JsonKey(name: 'is_active')
  final bool isActive;
  final List<String> tags;

  User({
    required this.id,
    required this.name,
    required this.email,
    required this.isActive,
    required this.tags,
  });

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

// Run code generation:
// dart run build_runner build --delete-conflicting-outputs
JavaScript (generate Dart classes from JSON)
function jsonToDart(obj, name = "Root") {
  const classes = [];
  function infer(val, fieldName) {
    if (val === null) return "dynamic";
    if (typeof val === "string") return "String";
    if (typeof val === "number") return Number.isInteger(val) ? "int" : "double";
    if (typeof val === "boolean") return "bool";
    if (Array.isArray(val)) {
      const first = val.find(v => v !== null);
      if (!first) return "List<dynamic>";
      return `List<${infer(first, fieldName)}>`;
    }
    if (typeof val === "object") {
      const cls = fieldName.charAt(0).toUpperCase() + fieldName.slice(1);
      build(val, cls);
      return cls;
    }
    return "dynamic";
  }
  function build(obj, cls) {
    const fields = Object.entries(obj).map(([k, v]) =>
      `  final ${infer(v, k)} ${k};`
    );
    classes.push(`class ${cls} {\n${fields.join("\n")}\n}`);
  }
  build(obj, name);
  return classes.join("\n\n");
}

console.log(jsonToDart({ id: 1, name: "Alice", scores: [98, 85] }, "User"));
// class User {
//   final int id;
//   final String name;
//   final List<int> scores;
// }
Python (generate Dart model from JSON)
import json

def json_to_dart(obj: dict, class_name: str = "Root") -> str:
    classes = []

    def infer(val, name):
        if val is None:
            return "dynamic"
        if isinstance(val, bool):
            return "bool"
        if isinstance(val, int):
            return "int"
        if isinstance(val, float):
            return "double"
        if isinstance(val, str):
            return "String"
        if isinstance(val, list):
            if not val:
                return "List<dynamic>"
            return f"List<{infer(val[0], name)}>"
        if isinstance(val, dict):
            cls = name[0].upper() + name[1:]
            build(val, cls)
            return cls
        return "dynamic"

    def build(obj, cls):
        fields = [f"  final {infer(v, k)} {k};" for k, v in obj.items()]
        classes.append(f"class {cls} {{\n" + "\n".join(fields) + "\n}")

    build(obj, class_name)
    return "\n\n".join(classes)

data = json.loads('{"id": 1, "name": "Alice", "active": true}')
print(json_to_dart(data, "User"))
# class User {
#   final int id;
#   final String name;
#   final bool active;
# }

Domande frequenti

Perché Flutter non può usare dart:mirrors per la deserializzazione JSON?
Flutter disabilita dart:mirrors (la libreria di reflection) perché il tree-shaking richiede di sapere in fase di compilazione quale codice viene usato. La reflection impedirebbe al compilatore di rimuovere le classi inutilizzate, aumentando le dimensioni dell'app. Per questo motivo i progetti Flutter necessitano di metodi fromJson/toJson espliciti o di generazione di codice invece della reflection a runtime.
Devo usare json_serializable o scrivere fromJson a mano?
Per progetti con meno di 10 classi modello, scrivere fromJson/toJson a mano è semplice e non aggiunge dipendenze di build. Quando si superano i 10 modelli, o i modelli cambiano frequentemente, json_serializable risparmia tempo e riduce gli errori di copia-incolla. Genera il codice di mappatura dalle annotazioni, quindi le aggiunte di campi richiedono solo di rieseguire build_runner.
Come gestisce il convertitore gli oggetti JSON annidati?
Ogni oggetto JSON annidato diventa una classe Dart separata. Se un campo JSON chiamato "address" contiene un oggetto con le chiavi "street" e "city", il convertitore crea una classe Address con quei campi e tipizza il campo del genitore come Address. La factory fromJson esegue il cast della mappa annidata e la passa ad Address.fromJson.
Cosa succede quando un campo JSON è null?
I campi null vengono tipizzati come dynamic con un suffisso ? perché il convertitore non può determinare il tipo previsto da un valore null da solo. Sostituisci dynamic? con il tipo corretto (String?, int?, ecc.) una volta che lo conosci dal tuo contratto API. La null safety di Dart imporrà quindi i controlli null corretti in fase di compilazione.
Come gestisco le chiavi JSON che non sono identificatori Dart validi?
Chiavi JSON come "first-name" o "2nd_place" non sono nomi di campo Dart validi. Con fromJson manuale, puoi mappare qualsiasi chiave JSON a qualsiasi nome di campo Dart nella factory constructor. Con json_serializable, usa @JsonKey(name: 'first-name') per annotare il campo. Il convertitore converte automaticamente i nomi delle chiavi in campi Dart in camelCase.
Posso usare freezed con l'output di questo strumento?
Lo strumento genera classi Dart standard con fromJson/toJson manuale. Per convertire a freezed, cambia la classe per usare l'annotazione @freezed, rimuovi il costruttore e la factory scritti a mano e aggiungi il mixin freezed. Poi esegui build_runner per generare i file .freezed.dart e .g.dart. I nomi dei campi e i tipi dell'output generato si trasferiscono direttamente.
Qual è la differenza tra una mappa grezza e una classe Dart tipizzata per JSON?
Una mappa grezza (Map di String a dynamic) ti dà accesso diretto ai dati JSON senza controllo dei tipi. Devi eseguire il cast di ogni valore nel punto di utilizzo, e gli errori di battitura nei nomi delle chiavi falliscono silenziosamente a runtime. Una classe Dart tipizzata intercetta le discordanze di tipo al confine fromJson, fornisce il completamento automatico dell'IDE per i nomi dei campi e rende il refactoring sicuro. La differenza di prestazioni è trascurabile; il beneficio riguarda interamente la correttezza e la manutenibilità.