JSON do Dart

Generuj klasy Dart z JSON z metodami fromJson i toJson

Wypróbuj przykład
Nazwa głównej klasy:

Wejście JSON

Wyjście Dart

Działa lokalnie · Bezpieczne do wklejania sekretów
Klasy Dart pojawią się tutaj…

Czym jest konwersja JSON do Dart?

Konwersja JSON do Dart pobiera surowy obiekt JSON i produkuje definicje klas Dart z typowanymi polami, nazwanym konstruktorem, fabryką fromJson i metodą toJson. Dart nie obsługuje refleksji w czasie wykonania we Flutterze (dart:mirrors jest wyłączony), więc nie można deserializować JSON do typowanych obiektów bez jawnego kodu mapującego. Każda odpowiedź REST API, dokument Firebase czy ładunek konfiguracyjny wymaga odpowiedniej klasy modelu Dart, zanim możliwy będzie dostęp do jej pól z bezpieczeństwem typów.

Typowa klasa modelu Dart dla JSON deklaruje pola final dla każdego klucza, konstruktor z nazwanymi parametrami (ze słowem kluczowym required dla pól non-nullable), konstruktor fabryczny fromJson odczytujący z Map<String, dynamic> oraz metodę toJson zwracającą Map<String, dynamic>. Zagnieżdżone obiekty JSON stają się osobnymi klasami. Tablice stają się typowanymi polami List. Wartości nullable w JSON używają składni null-safety Darta z sufiksem ? przy typie.

Ręczne pisanie tych klas modelu wymaga odczytania każdego klucza JSON, ustalenia typu Darta, stworzenia rzutowania fromJson dla każdego pola (łącznie z mapowaniem list przez .map().toList()), zbudowania literału mapy toJson i powtórzenia tego dla każdego zagnieżdżonego obiektu. Dla obiektu JSON z 12 polami i 2 zagnieżdżonymi obiektami oznacza to 3 klasy, 6 linii fabryk i dziesiątki wyrażeń rzutowania. Konwerter produkuje to wszystko w milisekundy z jednego wklejenia.

Dlaczego warto używać konwertera JSON do Dart?

Ręczne pisanie klas modelu Dart z JSON wymaga odczytywania nazw pól, zgadywania typów z przykładowych wartości, pisania rzutowań fromJson z poprawną obsługą null i powtarzania tego procesu dla zagnieżdżonych obiektów. Gdy kształt API się zmienia, każda aktualizacja pola dotyka konstruktora, fromJson i toJson. Konwerter eliminuje tę powtarzalną pracę.

Natychmiastowe generowanie klas
Wklej JSON i otrzymaj kompletne klasy Dart z konstruktorami, fabrykami fromJson i metodami toJson w mniej niż sekundę. Zagnieżdżone obiekty i listy są wykrywane i mapowane automatycznie.
🔒
Przetwarzanie z zachowaniem prywatności
Konwersja odbywa się w całości w przeglądarce przy użyciu JavaScript. Twoje dane JSON nigdy nie opuszczają Twojego urządzenia. Klucze API, tokeny i ładunki produkcyjne pozostają prywatne.
📝
Wyjście zgodne z null safety
Wygenerowane klasy używają solidnego systemu null safety Darta. Pola nullable JSON otrzymują sufiks ? przy typie i pomijają słowo kluczowe required w konstruktorach. Pola non-null są oznaczane jako required.
📦
Bez instalacji i rejestracji
Otwórz stronę i wklej JSON. Bez Dart SDK, bez zależności pub, bez konta. Działa na każdym urządzeniu z przeglądarką.

Przypadki użycia konwertera JSON do Dart

Tworzenie aplikacji Flutter
Generuj klasy modelu dla odpowiedzi REST API konsumowanych przez pakiety http lub dio. Wklej JSON zwracany przez backend i otrzymaj klasy Dart gotowe do jsonDecode i renderowania widżetów.
Integracja z Firebase / Firestore
Twórz typowane klasy modelu dla migawek dokumentów Firestore. Wklej przykładowy dokument jako JSON, wygeneruj klasę Dart i użyj fromJson z snapshot.data() w warstwie repozytorium.
Modele zarządzania stanem
Definiuj typowane obiekty stanu dla Riverpod, Bloc lub Provider. Wklej oczekiwany kształt stanu jako JSON i otrzymaj niezmienne klasy Dart z toJson do utrwalania i hydratacji stanu.
Generowanie kodu klienta API
Twórz modele żądań i odpowiedzi dla klientów API Retrofit lub Chopper. Wklej przykładowe ładunki JSON i otrzymaj klasy Dart pasujące do schematów odpowiedzi OpenAPI.
Testowanie automatyczne
Buduj typowane dane testowe z rzeczywistych odpowiedzi API. Wklej próbkę JSON, wygeneruj klasę modelu i używaj jej bezpośrednio w testach jednostkowych i widżetów bez ręcznego pisania struktur danych testowych.
Nauka wzorców Darta
Studenci uczący się Fluttera mogą wklejać dowolną strukturę JSON i obserwować, jak Dart ją reprezentuje: pola final, nazwane konstruktory, wzorce fabryki fromJson i adnotacje null-safety w praktyce.

Mapowanie typów JSON do Dart

Każda wartość JSON mapuje się na konkretny typ Darta. Poniższa tabela pokazuje, jak konwerter tłumaczy każdy typ JSON. Kolumna Alternatywa pokazuje typy używane w rzadszych lub ręcznych scenariuszach mapowania.

Typ JSONPrzykładTyp DartAlternatywa
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>

Podejścia do serializacji JSON w Darcie

Dart i Flutter oferują wiele sposobów obsługi serializacji JSON. Ręczne fromJson/toJson to najprostsze podejście niewymagające generowania kodu. W większych projektach rozwiązania oparte na build_runner, takie jak json_serializable i freezed, generują szablonowy kod podczas kompilacji, zmniejszając liczbę błędów i utrzymując modele zgodne z kontraktem JSON.

PodejścieOpisŹródło
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

Porównanie: ręcznie, json_serializable, freezed

Dart ma trzy popularne podejścia do klas modelu JSON. Ręczne fromJson/toJson nie ma żadnych zależności. json_serializable automatyzuje kod mapowania. freezed dodaje niezmienność, copyWith i dopasowanie wzorców na bazie json_serializable.

Manual fromJson/toJson
Pisz fabryki fromJson i metody toJson ręcznie. Zero zależności, brak kroku build_runner. Masz pełną kontrolę nad logiką rzutowania i obsługą błędów. Najlepsze dla małych projektów z kilkoma modelami lub gdy potrzebujesz niestandardowej deserializacji, której generatory kodu nie potrafią wyrazić. To format wyjściowy generowany przez to narzędzie.
json_serializable
Opatrz klasę adnotacją @JsonSerializable() i uruchom dart run build_runner build. Generator tworzy plik .g.dart z funkcjami _$ClassFromJson i _$ClassToJson. Obsługuje @JsonKey do zmiany nazw pól, wartości domyślnych i niestandardowych konwerterów. Standardowy wybór dla średnich i dużych projektów Flutter.
freezed
Opatrz adnotacją @freezed i otrzymaj niezmienne klasy z fromJson, toJson, copyWith, równością (== i hashCode) oraz toString generowanymi automatycznie. Obsługuje typy unii dla wzorców sealed class. Wymaga zarówno freezed, jak i json_serializable jako zależności deweloperskie. Najlepsze dla modeli zarządzania stanem i złożonych obiektów domenowych.

Przykłady kodu

Te przykłady pokazują, jak używać wygenerowanych klas Dart do deserializacji JSON, jak skonfigurować json_serializable z build_runner oraz jak generować klasy Dart programowo z JavaScript i 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;
# }

Często zadawane pytania

Dlaczego Flutter nie może używać dart:mirrors do deserializacji JSON?
Flutter wyłącza dart:mirrors (bibliotekę refleksji), ponieważ eliminacja martwego kodu (tree-shaking) wymaga znajomości używanego kodu już na etapie kompilacji. Refleksja uniemożliwiłaby kompilatorowi usuwanie nieużywanych klas, zwiększając rozmiar aplikacji. Dlatego projekty Flutter wymagają jawnych metod fromJson/toJson lub generowania kodu zamiast refleksji w czasie wykonania.
Czy powinienem używać json_serializable, czy pisać fromJson ręcznie?
W projektach z mniej niż 10 klasami modelu ręczne fromJson/toJson jest proste i nie dodaje zależności do kompilacji. Gdy masz więcej niż 10 modeli lub modele, które często się zmieniają, json_serializable oszczędza czas i zmniejsza liczbę błędów copy-paste. Generuje kod mapowania z adnotacji, więc dodanie pola wymaga jedynie ponownego uruchomienia build_runner.
Jak konwerter obsługuje zagnieżdżone obiekty JSON?
Każdy zagnieżdżony obiekt JSON staje się osobną klasą Dart. Jeśli pole JSON o nazwie "address" zawiera obiekt z kluczami "street" i "city", konwerter tworzy klasę Address z tymi polami i typuje pole rodzica jako Address. Fabryka fromJson rzutuje zagnieżdżoną mapę i przekazuje ją do Address.fromJson.
Co się dzieje, gdy pole JSON jest null?
Pola null są typowane jako dynamic z sufiksem ?, ponieważ konwerter nie może ustalić zamierzonego typu na podstawie samej wartości null. Zastąp dynamic? właściwym typem (String?, int? itp.), gdy znasz go z kontraktu API. Null safety Darta będzie wtedy wymuszać poprawne sprawdzanie null podczas kompilacji.
Jak obsługiwać klucze JSON, które nie są prawidłowymi identyfikatorami Darta?
Klucze JSON takie jak "first-name" lub "2nd_place" nie są prawidłowymi nazwami pól Darta. Przy ręcznym fromJson możesz mapować dowolny klucz JSON na dowolną nazwę pola Darta w konstruktorze fabrycznym. Przy json_serializable użyj @JsonKey(name: 'first-name') do opatrzenia pola adnotacją. Konwerter automatycznie konwertuje nazwy kluczy na pola Darta w camelCase.
Czy mogę użyć freezed z wyjściem tego narzędzia?
Narzędzie generuje standardowe klasy Dart z ręcznym fromJson/toJson. Aby przekonwertować na freezed, zmień klasę na używającą adnotacji @freezed, usuń ręcznie napisany konstruktor i fabrykę, a następnie dodaj mixin freezed. Następnie uruchom build_runner, aby wygenerować pliki .freezed.dart i .g.dart. Nazwy pól i typy z wygenerowanego wyjścia przenoszą się bezpośrednio.
Jaka jest różnica między surową mapą a typowaną klasą Dart dla JSON?
Surowa mapa (Map<String, dynamic>) daje surowy dostęp do danych JSON bez sprawdzania typów. Musisz rzutować każdą wartość w miejscu wywołania, a literówki w nazwach kluczy cicho zawodzą w czasie wykonania. Typowana klasa Dart wychwytuje niezgodności typów na granicy fromJson, zapewnia automatyczne uzupełnianie nazw pól w IDE i sprawia, że refaktoryzacja jest bezpieczna. Różnica w wydajności jest nieistotna; korzyść dotyczy wyłącznie poprawności i łatwości utrzymania.