Die Konvertierung von JSON in Dart Model-Klassen ist eine der häufigsten Aufgaben in der Flutter-Entwicklung.
Warum Model-Klassen
Grundlegende JSON-zu-Dart-Typzuordnung
| JSON-Typ | Dart-Typ | Beispiel |
|---|---|---|
| string | String | "hello" → "hello" |
| number (int) | int | 42 → 42 |
| number (float) | double | 3.14 → 3.14 |
| boolean | bool | true → true |
| null | Null / dynamic | null → null |
| array | List<T> | [1,2,3] → [1,2,3] |
| object | Map / Class | {} → User() |
Manuelle Model-Klasse (fromJson / toJson)
Der einfachste Ansatz ist, Model-Klassen von Hand zu schreiben:
// JSON input
{
"id": 1,
"name": "John Doe",
"email": "john@example.com",
"isActive": true,
"score": 95.5
}
// Dart model class
class User {
final int id;
final String name;
final String email;
final bool isActive;
final double score;
User({
required this.id,
required this.name,
required this.email,
required this.isActive,
required this.score,
});
factory User.fromJson(Map<String, dynamic> json) {
return User(
id: json['id'] as int,
name: json['name'] as String,
email: json['email'] as String,
isActive: json['isActive'] as bool,
score: (json['score'] as num).toDouble(),
);
}
Map<String, dynamic> toJson() {
return {
'id': id,
'name': name,
'email': email,
'isActive': isActive,
'score': score,
};
}
}Verschachtelte Objekte behandeln
Erstellen Sie separate Dart-Klassen für jede Verschachtelungsebene:
// JSON with nested object
{
"id": 1,
"name": "John",
"address": {
"street": "123 Main St",
"city": "Springfield",
"zipCode": "62701"
}
}
// Dart classes
class Address {
final String street;
final String city;
final String zipCode;
Address({required this.street, required this.city, required this.zipCode});
factory Address.fromJson(Map<String, dynamic> json) {
return Address(
street: json['street'] as String,
city: json['city'] as String,
zipCode: json['zipCode'] as String,
);
}
Map<String, dynamic> toJson() => {
'street': street, 'city': city, 'zipCode': zipCode,
};
}
class User {
final int id;
final String name;
final Address address;
User({required this.id, required this.name, required this.address});
factory User.fromJson(Map<String, dynamic> json) {
return User(
id: json['id'] as int,
name: json['name'] as String,
address: Address.fromJson(json['address'] as Map<String, dynamic>),
);
}
Map<String, dynamic> toJson() => {
'id': id, 'name': name, 'address': address.toJson(),
};
}Listen und Arrays behandeln
JSON-Arrays werden zu Dart-List-Typen:
// JSON with arrays
{
"name": "John",
"hobbies": ["coding", "reading", "gaming"],
"orders": [
{"id": 1, "product": "Laptop", "price": 999.99},
{"id": 2, "product": "Mouse", "price": 29.99}
]
}
// Dart
class User {
final String name;
final List<String> hobbies;
final List<Order> orders;
User({required this.name, required this.hobbies, required this.orders});
factory User.fromJson(Map<String, dynamic> json) {
return User(
name: json['name'] as String,
hobbies: List<String>.from(json['hobbies'] as List),
orders: (json['orders'] as List)
.map((e) => Order.fromJson(e as Map<String, dynamic>))
.toList(),
);
}
}Null Safety Best Practices
Mit Darts Null Safety müssen nullable Felder korrekt behandelt werden:
- Verwenden Sie `required` für Pflichtfelder
- Verwenden Sie `?` für nullable Typen
- Standardwerte mit `??` bereitstellen
- `late` nur verwenden wenn Initialisierung sicher ist
class User {
final int id;
final String name;
final String? bio; // nullable
final String avatarUrl; // with default
User({
required this.id,
required this.name,
this.bio,
this.avatarUrl = 'https://example.com/default-avatar.png',
});
factory User.fromJson(Map<String, dynamic> json) {
return User(
id: json['id'] as int,
name: json['name'] as String,
bio: json['bio'] as String?,
avatarUrl: json['avatarUrl'] as String? ?? 'https://example.com/default-avatar.png',
);
}
}json_serializable verwenden
Für größere Projekte automatisiert json_serializable den Boilerplate-Code:
Schritt 1: Dependencies hinzufügen
# pubspec.yaml
dependencies:
json_annotation: ^4.8.1
dev_dependencies:
json_serializable: ^6.7.1
build_runner: ^2.4.6Schritt 2: Model mit Annotationen erstellen
import 'package:json_annotation/json_annotation.dart';
part 'user.g.dart';
@JsonSerializable()
class User {
final int id;
final String name;
final String email;
@JsonKey(name: 'is_active')
final bool isActive;
@JsonKey(defaultValue: 0.0)
final double score;
User({
required this.id,
required this.name,
required this.email,
required this.isActive,
required this.score,
});
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
Map<String, dynamic> toJson() => _$UserToJson(this);
}Schritt 3: Build Runner ausführen
dart run build_runner build --delete-conflicting-outputsFreezed für unveränderliche Models
Das freezed-Paket generiert unveränderliche Klassen mit copyWith und JSON-Serialisierung:
import 'package:freezed_annotation/freezed_annotation.dart';
part 'user.freezed.dart';
part 'user.g.dart';
@freezed
class User with _$User {
const factory User({
required int id,
required String name,
required String email,
@Default(false) bool isActive,
}) = _User;
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
}Häufige Fehler und Lösungen
| Fehler | Lösung |
|---|---|
| `json['key']` ohne Null-Check | `json['key'] as String? ?? ''` verwenden |
| Verschachtelte Objekte vergessen | `NestedClass.fromJson()` aufrufen |
| `int` für alle Zahlen | `num` verwenden und konvertieren |
| Fehlende Schlüssel nicht behandeln | `containsKey()` oder Standardwerte verwenden |
| Falscher Typ in toJson | Verschachtelte Objekte rufen `.toJson()` auf |
FAQ
Was ist der beste Weg JSON in Dart-Klassen umzuwandeln?
Kleine Projekte: manuell. Große Projekte: json_serializable oder freezed.
Wie behandle ich dynamische JSON-Schlüssel?
Verwenden Sie Map<String, dynamic>.
json_serializable oder freezed?
json_serializable für einfache Serialisierung, freezed für Unveränderlichkeit.
Wie behandle ich Datumsangaben?
DateTime.parse() für ISO 8601-Strings verwenden.