JSON to Dart

Dart-Klassen aus JSON mit fromJson und toJson generieren

Beispiel ausprobieren
Name der Root-Klasse:

JSON-Eingabe

Dart-Ausgabe

Läuft lokal · Sicher zum Einfügen von Secrets
Dart-Klassen erscheinen hier…

Was ist die JSON-zu-Dart-Konvertierung?

Die JSON-zu-Dart-Konvertierung nimmt ein rohes JSON-Objekt und erzeugt daraus Dart-Klassendefinitionen mit typisierten Feldern, einem benannten Konstruktor, einer fromJson-Factory und einer toJson-Methode. Dart verfügt in Flutter über keine Laufzeit-Reflection (dart:mirrors ist deaktiviert), daher können JSON-Daten nicht ohne expliziten Mapping-Code in typisierte Objekte deserialisiert werden. Jede REST-API-Antwort, jedes Firestore-Dokument und jeder Konfigurations-Payload benötigt eine entsprechende Dart-Modellklasse, bevor man typsicher auf die Felder zugreifen kann.

Eine typische Dart-Modellklasse für JSON deklariert finale Felder für jeden Schlüssel, einen Konstruktor mit benannten Parametern (mit dem required-Schlüsselwort für nicht-nullable Felder), eine Factory-Methode namens fromJson, die aus einer Map<String, dynamic> liest, sowie eine toJson-Methode, die eine Map<String, dynamic> zurückgibt. Verschachtelte JSON-Objekte werden zu separaten Klassen. Arrays werden zu typisierten List-Feldern. Nullable JSON-Werte verwenden Darts Null-Safety-Syntax mit dem ?-Suffix am Typ.

Diese Modellklassen von Hand zu schreiben bedeutet: jeden JSON-Schlüssel lesen, den Dart-Typ festlegen, den fromJson-Cast für jedes Feld erstellen (einschließlich Listen-Mapping mit .map().toList()), ein toJson-Map-Literal erstellen und das Ganze für jedes verschachtelte Objekt wiederholen. Bei einem JSON-Objekt mit 12 Feldern und 2 verschachtelten Objekten entstehen 3 Klassen, 6 Factory-Zeilen und dutzende Cast-Ausdrücke. Ein Konverter erzeugt all das in Millisekunden aus einem einzigen Einfügevorgang.

Warum einen JSON-zu-Dart-Konverter verwenden?

Dart-Modellklassen manuell aus JSON zu erstellen bedeutet: Feldnamen lesen, Typen aus Beispielwerten ableiten, fromJson-Casts mit korrekter Null-Behandlung schreiben und diesen Prozess für verschachtelte Objekte wiederholen. Ändert sich die API-Struktur, muss jede Feldaktualisierung im Konstruktor, in fromJson und in toJson angepasst werden. Ein Konverter nimmt diese repetitive Arbeit ab.

Sofortige Klassengenerierung
JSON einfügen und vollständige Dart-Klassen mit Konstruktoren, fromJson-Factories und toJson-Methoden in unter einer Sekunde erhalten. Verschachtelte Objekte und Listen werden automatisch erkannt und abgebildet.
🔒
Datenschutz-First-Verarbeitung
Die Konvertierung läuft vollständig im Browser per JavaScript. Die JSON-Daten verlassen das eigene Gerät nicht. API-Keys, Tokens und Produktionsdaten bleiben privat.
📝
Null-sichere Ausgabe
Generierte Klassen verwenden Darts Sound Null Safety. Nullable JSON-Felder erhalten das ?-Typ-Suffix und verzichten auf das required-Schlüsselwort im Konstruktor. Nicht-nullable Felder werden als required markiert.
📦
Keine Installation oder Registrierung
Seite öffnen und JSON einfügen. Kein Dart SDK, keine pub-Abhängigkeiten, kein Konto. Funktioniert auf jedem Gerät mit einem Browser.

JSON-zu-Dart-Anwendungsfälle

Flutter-App-Entwicklung
Modellklassen für REST-API-Antworten generieren, die von http- oder dio-Paketen verarbeitet werden. Das vom Backend zurückgelieferte JSON einfügen und Dart-Klassen erhalten, die für jsonDecode und das Rendern von Widgets bereit sind.
Firebase / Firestore-Integration
Typisierte Modellklassen für Firestore-Dokument-Snapshots erstellen. Ein Beispieldokument als JSON einfügen, die Dart-Klasse generieren und fromJson mit snapshot.data() in der Repository-Schicht verwenden.
State-Management-Modelle
Typisierte State-Objekte für Riverpod, Bloc oder Provider definieren. Die erwartete State-Struktur als JSON einfügen und unveränderliche Dart-Klassen mit toJson für State-Persistenz und Hydration erhalten.
API-Client-Code-Generierung
Request- und Response-Modelle für Retrofit- oder Chopper-API-Clients erzeugen. Beispiel-JSON-Payloads einfügen und Dart-Klassen erhalten, die den OpenAPI-Response-Schemas entsprechen.
Automatisiertes Testen
Typisierte Test-Fixtures aus echten API-Antworten erstellen. Ein JSON-Beispiel einfügen, die Modellklasse generieren und diese direkt in Unit- und Widget-Tests verwenden, ohne Fixture-Strukturen von Hand zu schreiben.
Dart-Muster erlernen
Lernende können beliebige JSON-Strukturen einfügen und sehen, wie Dart diese abbildet: finale Felder, benannte Konstruktoren, fromJson-Factory-Muster und Null-Safety-Annotationen in der Praxis.

JSON-zu-Dart-Typ-Mapping

Jeder JSON-Wert wird auf einen bestimmten Dart-Typ abgebildet. Die folgende Tabelle zeigt, wie der Konverter jeden JSON-Typ übersetzt. Die Spalte Alternative zeigt Typen, die in selteneren oder manuellen Mapping-Szenarien verwendet werden.

JSON-TypBeispielDart-TypAlternative
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>

Dart-JSON-Serialisierungsansätze

Dart und Flutter bieten mehrere Möglichkeiten zur JSON-Serialisierung. Manuelles fromJson/toJson ist der einfachste Ansatz und erfordert keine Code-Generierung. Für größere Projekte erzeugen build_runner-basierte Lösungen wie json_serializable und freezed den Boilerplate zur Compile-Zeit, reduzieren Fehler und halten die Modelle konsistent mit dem JSON-Vertrag.

AnsatzBeschreibungQuelle
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

Manuell vs. json_serializable vs. freezed

Dart bietet drei gängige Ansätze für JSON-Modellklassen. Manuelles fromJson/toJson kommt ohne Abhängigkeiten aus. json_serializable automatisiert den Mapping-Code. freezed fügt Unveränderlichkeit, copyWith und Pattern-Matching auf Basis von json_serializable hinzu.

Manual fromJson/toJson
fromJson-Factories und toJson-Methoden von Hand schreiben. Keine Abhängigkeiten, kein build_runner-Schritt. Volle Kontrolle über die Cast-Logik und Fehlerbehandlung. Optimal für kleine Projekte mit wenigen Modellen oder wenn benutzerdefinierte Deserialisierung benötigt wird, die Code-Generatoren nicht ausdrücken können. Dies ist das Ausgabeformat dieses Tools.
json_serializable
Die Klasse mit @JsonSerializable() annotieren und dart run build_runner build ausführen. Der Generator erstellt eine .g.dart-Datei mit den Funktionen _$ClassFromJson und _$ClassToJson. Unterstützt @JsonKey für Feldumbenennung, Standardwerte und benutzerdefinierte Konverter. Die Standardwahl für mittlere bis große Flutter-Projekte.
freezed
Mit @freezed annotieren und unveränderliche Klassen mit fromJson, toJson, copyWith, Gleichheit (== und hashCode) sowie toString erhalten, die automatisch generiert werden. Unterstützt Union-Typen für Sealed-Class-Muster. Erfordert sowohl freezed als auch json_serializable als dev-Abhängigkeiten. Optimal für State-Management-Modelle und komplexe Domain-Objekte.

Code-Beispiele

Diese Beispiele zeigen, wie generierte Dart-Klassen für die JSON-Deserialisierung verwendet werden, wie json_serializable mit build_runner eingerichtet wird und wie Dart-Klassen programmatisch aus JavaScript und Python erzeugt werden.

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;
# }

Häufig gestellte Fragen

Warum kann Flutter dart:mirrors für die JSON-Deserialisierung nicht verwenden?
Flutter deaktiviert dart:mirrors (die Reflection-Bibliothek), weil Tree-Shaking zur Compile-Zeit wissen muss, welcher Code verwendet wird. Reflection würde verhindern, dass der Compiler ungenutzte Klassen entfernt, was die App-Größe erhöhen würde. Deshalb benötigen Flutter-Projekte explizite fromJson/toJson-Methoden oder Code-Generierung statt Laufzeit-Reflection.
Sollte ich json_serializable verwenden oder fromJson von Hand schreiben?
Bei Projekten mit weniger als 10 Modellklassen ist manuelles fromJson/toJson unkompliziert und fügt keine Build-Abhängigkeiten hinzu. Ab mehr als 10 Modellen oder bei häufig geänderten Modellen spart json_serializable Zeit und reduziert Copy-Paste-Fehler. Der Mapping-Code wird aus Annotationen generiert, sodass Feldergänzungen nur einen erneuten build_runner-Lauf erfordern.
Wie behandelt der Konverter verschachtelte JSON-Objekte?
Jedes verschachtelte JSON-Objekt wird zu einer eigenen Dart-Klasse. Enthält ein JSON-Feld namens "address" ein Objekt mit den Schlüsseln "street" und "city", erstellt der Konverter eine Address-Klasse mit diesen Feldern und typisiert das übergeordnete Feld als Address. Die fromJson-Factory castet die verschachtelte Map und übergibt sie an Address.fromJson.
Was passiert, wenn ein JSON-Feld null ist?
Null-Felder werden als dynamic? typisiert, weil der Konverter den beabsichtigten Typ aus einem null-Wert allein nicht ableiten kann. Ersetze dynamic? durch den korrekten Typ (String?, int? usw.), sobald er aus dem API-Vertrag bekannt ist. Darts Null Safety erzwingt dann korrekte Null-Prüfungen zur Compile-Zeit.
Wie gehe ich mit JSON-Schlüsseln um, die keine gültigen Dart-Bezeichner sind?
JSON-Schlüssel wie "first-name" oder "2nd_place" sind keine gültigen Dart-Feldnamen. Mit manuellem fromJson lässt sich jeder JSON-Schlüssel in der Factory auf einen beliebigen Dart-Feldnamen abbilden. Mit json_serializable verwendet man @JsonKey(name: 'first-name') zur Annotation des Feldes. Der Konverter konvertiert Schlüsselnamen automatisch in camelCase-Dart-Felder.
Kann ich freezed mit der Ausgabe dieses Tools verwenden?
Das Tool generiert Standard-Dart-Klassen mit manuellem fromJson/toJson. Für die Umstellung auf freezed die Klasse mit der @freezed-Annotation versehen, den handgeschriebenen Konstruktor und die Factory entfernen und den freezed-Mixin hinzufügen. Danach build_runner ausführen, um die .freezed.dart- und .g.dart-Dateien zu generieren. Feldnamen und Typen aus der generierten Ausgabe werden direkt übernommen.
Was ist der Unterschied zwischen einer rohen Map und einer typisierten Dart-Klasse für JSON?
Eine rohe Map (Map<String, dynamic>) ermöglicht den direkten Zugriff auf JSON-Daten ohne Typprüfung. Jeder Wert muss an der Aufrufstelle gecastet werden, und Tippfehler bei Schlüsselnamen schlagen erst zur Laufzeit still fehl. Eine typisierte Dart-Klasse erkennt Typ-Mismatches an der fromJson-Grenze, bietet IDE-Autovervollständigung für Feldnamen und macht Refactoring sicher. Der Leistungsunterschied ist vernachlässigbar; der Vorteil liegt vollständig in Korrektheit und Wartbarkeit.