[{"data":1,"prerenderedAt":77},["ShallowReactive",2],{"tutorial-serializzazione-json-avanzata-in-flutter-con-json-serializable-e-build-runner":3,"comments-tutorial-serializzazione-json-avanzata-in-flutter-con-json-serializable-e-build-runner":76},{"id":4,"title":5,"slug":6,"excerpt":7,"intro":8,"cover_image":9,"video_url":10,"difficulty":11,"estimated_minutes":12,"flutter_version":13,"status":14,"published_at":15,"meta_title":16,"meta_description":17,"category":18,"author":22,"steps":25},53,"Serializzazione JSON avanzata in Flutter con json_serializable e build_runner","serializzazione-json-avanzata-in-flutter-con-json-serializable-e-build-runner","Impara a generare automaticamente il codice di serializzazione e deserializzazione JSON in Flutter usando json_serializable, evitando errori manuali e boilerplate ripetitivo.","## Perché automatizzare la serializzazione JSON?\n\nQuando la tua app comunica con delle API, devi convertire continuamente oggetti Dart in JSON e viceversa. Scrivere a mano i metodi `fromJson` e `toJson` è noioso, ripetitivo e soggetto a errori, soprattutto con modelli complessi e nidificati.\n\nIn questo tutorial vedremo come usare i pacchetti `json_serializable` e `build_runner` per **generare automaticamente** il codice di serializzazione. Copriremo la configurazione, i campi rinominati, gli oggetti annidati, le liste e i valori di default. Al termine avrai un flusso di lavoro solido e manutenibile per gestire il JSON nelle tue app.","https:\u002F\u002Fflutter.it\u002Fstorage\u002Ftutorials\u002Faf72f88a-e706-4770-8413-8a51494ff2e7.jpg",null,"intermediate",35,"3.x","published","2026-08-04T04:30:49+00:00","Serializzazione JSON in Flutter con json_serializable","Genera automaticamente fromJson e toJson in Flutter con json_serializable e build_runner: modelli annidati, liste e valori di default.",{"id":19,"name":20,"slug":21},3,"Best practice","best-practice",{"id":23,"name":24},1,"Flutter Bot",[26,33,41,48,55,62,69],{"id":27,"position":23,"title":28,"body":29,"code_snippet":30,"code_language":31,"expected_result":32,"demo_url":10,"video_url":10},357,"Aggiungere le dipendenze al progetto","Per prima cosa aggiungiamo le dipendenze necessarie. `json_annotation` è una dipendenza di runtime che fornisce le annotazioni, mentre `json_serializable` e `build_runner` sono dipendenze di sviluppo usate solo per generare il codice.\n\nApri il file `pubspec.yaml` e aggiungi le righe seguenti, oppure esegui i comandi da terminale:\n\n```bash\nflutter pub add json_annotation\nflutter pub add dev:build_runner\nflutter pub add dev:json_serializable\n```","dependencies:\n  flutter:\n    sdk: flutter\n  json_annotation: ^4.9.0\n\ndev_dependencies:\n  build_runner: ^2.4.13\n  json_serializable: ^6.9.0","yaml","Eseguendo `flutter pub get` le dipendenze vengono scaricate senza errori.",{"id":34,"position":35,"title":36,"body":37,"code_snippet":38,"code_language":39,"expected_result":40,"demo_url":10,"video_url":10},358,2,"Creare il modello con le annotazioni","Creiamo il file `lib\u002Fmodels\u002Fuser.dart`. La struttura chiave prevede tre elementi:\n\n1. La direttiva `part 'user.g.dart';` che collega il file generato.\n2. L'annotazione `@JsonSerializable()` sopra la classe.\n3. I due metodi `fromJson` e `toJson` che delegano alle funzioni generate.\n\nNon preoccuparti se l'IDE segnala un errore su `user.g.dart`: quel file non esiste ancora e verrà creato nel passo successivo.","import 'package:json_annotation\u002Fjson_annotation.dart';\n\npart 'user.g.dart';\n\n@JsonSerializable()\nclass User {\n  final int id;\n  final String name;\n  final String email;\n\n  User({\n    required this.id,\n    required this.name,\n    required this.email,\n  });\n\n  factory User.fromJson(Map\u003CString, dynamic> json) => _$UserFromJson(json);\n\n  Map\u003CString, dynamic> toJson() => _$UserToJson(this);\n}","dart","Il file compila a parte l'errore temporaneo su `_$UserFromJson` e `_$UserToJson`.",{"id":42,"position":19,"title":43,"body":44,"code_snippet":45,"code_language":46,"expected_result":47,"demo_url":10,"video_url":10},359,"Generare il codice con build_runner","Ora avviamo la generazione del codice. Esegui questo comando dalla radice del progetto:\n\n```bash\ndart run build_runner build --delete-conflicting-outputs\n```\n\nL'opzione `--delete-conflicting-outputs` rimuove eventuali file generati obsoleti evitando conflitti.\n\nDurante lo sviluppo puoi anche usare la modalità *watch*, che rigenera automaticamente i file a ogni modifica:\n\n```bash\ndart run build_runner watch --delete-conflicting-outputs\n```","dart run build_runner build --delete-conflicting-outputs","bash","Viene creato il file `lib\u002Fmodels\u002Fuser.g.dart` e gli errori nel modello scompaiono.",{"id":49,"position":50,"title":51,"body":52,"code_snippet":53,"code_language":39,"expected_result":54,"demo_url":10,"video_url":10},360,4,"Personalizzare i nomi dei campi","Le API spesso usano convenzioni di naming diverse da quelle di Dart (ad esempio `snake_case`). Con `@JsonKey(name: ...)` puoi mappare un campo JSON su una proprietà con nome diverso.\n\nIn alternativa, per convertire automaticamente tutte le chiavi in `snake_case`, puoi passare `fieldRename: FieldRename.snake` all'annotazione `@JsonSerializable`, evitando di annotare ogni singolo campo.\n\nDopo ogni modifica ricorda di rieseguire `build_runner`.","@JsonSerializable(fieldRename: FieldRename.snake)\nclass User {\n  final int id;\n  final String name;\n  final String email;\n\n  \u002F\u002F Mappato manualmente sul campo JSON \"avatar_url\"\n  @JsonKey(name: 'avatar_url')\n  final String? avatarUrl;\n\n  User({\n    required this.id,\n    required this.name,\n    required this.email,\n    this.avatarUrl,\n  });\n\n  factory User.fromJson(Map\u003CString, dynamic> json) => _$UserFromJson(json);\n  Map\u003CString, dynamic> toJson() => _$UserToJson(this);\n}","Il JSON con chiavi come `avatar_url` viene deserializzato correttamente in `avatarUrl`.",{"id":56,"position":57,"title":58,"body":59,"code_snippet":60,"code_language":39,"expected_result":61,"demo_url":10,"video_url":10},361,5,"Gestire oggetti annidati e liste","Il vero vantaggio di `json_serializable` emerge con i modelli complessi. Se un modello contiene altri oggetti annotati con `@JsonSerializable()`, la libreria gestisce automaticamente la serializzazione ricorsiva, incluse le liste di oggetti.\n\nCreiamo un modello `Post` che contiene un `User` come autore e una lista di `Comment`. Basta che anche `Comment` sia una classe annotata: non serve scrivere alcuna logica di conversione manuale.","import 'package:json_annotation\u002Fjson_annotation.dart';\nimport 'user.dart';\n\npart 'post.g.dart';\n\n@JsonSerializable(explicitToJson: true)\nclass Post {\n  final int id;\n  final String title;\n  final User author;\n  final List\u003CComment> comments;\n\n  Post({\n    required this.id,\n    required this.title,\n    required this.author,\n    required this.comments,\n  });\n\n  factory Post.fromJson(Map\u003CString, dynamic> json) => _$PostFromJson(json);\n  Map\u003CString, dynamic> toJson() => _$PostToJson(this);\n}\n\n@JsonSerializable()\nclass Comment {\n  final int id;\n  final String text;\n\n  Comment({required this.id, required this.text});\n\n  factory Comment.fromJson(Map\u003CString, dynamic> json) => _$CommentFromJson(json);\n  Map\u003CString, dynamic> toJson() => _$CommentToJson(this);\n}","Chiamando `post.toJson()` gli oggetti annidati vengono convertiti correttamente grazie a `explicitToJson: true`.",{"id":63,"position":64,"title":65,"body":66,"code_snippet":67,"code_language":39,"expected_result":68,"demo_url":10,"video_url":10},362,6,"Valori di default e campi calcolati","Spesso le API restituiscono campi opzionali o nulli. Con `@JsonKey(defaultValue: ...)` puoi definire un valore da usare quando la chiave è assente o `null`, rendendo il modello più robusto.\n\nPuoi anche escludere campi calcolati dalla serializzazione con `@JsonKey(includeFromJson: false, includeToJson: false)`, utile per proprietà derivate che non fanno parte del payload JSON.","@JsonSerializable()\nclass Product {\n  final int id;\n  final String name;\n\n  @JsonKey(defaultValue: 0.0)\n  final double price;\n\n  @JsonKey(defaultValue: true)\n  final bool available;\n\n  \u002F\u002F Campo calcolato: non incluso nel JSON\n  @JsonKey(includeFromJson: false, includeToJson: false)\n  String get displayLabel => '$name (\\u20AC$price)';\n\n  Product({\n    required this.id,\n    required this.name,\n    required this.price,\n    required this.available,\n  });\n\n  factory Product.fromJson(Map\u003CString, dynamic> json) => _$ProductFromJson(json);\n  Map\u003CString, dynamic> toJson() => _$ProductToJson(this);\n}","Se il JSON non contiene `price` o `available`, vengono usati i valori di default; `displayLabel` non compare nell'output di `toJson()`.",{"id":70,"position":71,"title":72,"body":73,"code_snippet":74,"code_language":39,"expected_result":75,"demo_url":10,"video_url":10},363,7,"Usare i modelli nella tua app","Infine mettiamo tutto insieme. Tipicamente riceverai una stringa JSON da un'API: usa `jsonDecode` da `dart:convert` per ottenere una `Map`, poi passala al factory `fromJson`. Per l'invio, converti con `toJson()` e poi `jsonEncode`.\n\nQuesto approccio ti garantisce codice generato, tipizzato e sempre allineato al modello, riducendo drasticamente i bug legati al parsing manuale.","import 'dart:convert';\nimport 'models\u002Fuser.dart';\n\nvoid main() {\n  \u002F\u002F Deserializzazione da stringa JSON\n  const jsonString = '{\"id\": 1, \"name\": \"Anna\", \"email\": \"anna@example.com\"}';\n  final Map\u003CString, dynamic> map = jsonDecode(jsonString);\n  final user = User.fromJson(map);\n  print('Utente: ${user.name}');\n\n  \u002F\u002F Serializzazione verso stringa JSON\n  final newUser = User(id: 2, name: 'Luca', email: 'luca@example.com');\n  final encoded = jsonEncode(newUser.toJson());\n  print(encoded);\n}","In console vengono stampati 'Utente: Anna' e la stringa JSON dell'oggetto `newUser`.",[],1785824426052]