JSON থেকে Dart
fromJson ও toJson সহ JSON থেকে Dart ক্লাস তৈরি করুন
JSON ইনপুট
Dart আউটপুট
JSON থেকে Dart রূপান্তর কী?
JSON থেকে Dart রূপান্তর একটি কাঁচা JSON অবজেক্ট নিয়ে টাইপড ফিল্ড, নামযুক্ত কনস্ট্রাক্টর, fromJson ফ্যাক্টরি এবং toJson মেথডসহ Dart ক্লাস ডেফিনিশন তৈরি করে। Flutter-এ Dart রানটাইম রিফ্লেকশন সমর্থন করে না (dart:mirrors নিষ্ক্রিয়), তাই স্পষ্ট ম্যাপিং কোড না লিখে JSON কে টাইপড অবজেক্টে রূপান্তর করা সম্ভব নয়। প্রতিটি REST API রেসপন্স, Firebase ডকুমেন্ট বা কনফিগ পেলোডের জন্য টাইপ সেফটি সহ ফিল্ড অ্যাক্সেস করতে একটি সংশ্লিষ্ট Dart মডেল ক্লাস প্রয়োজন।
JSON-এর জন্য একটি সাধারণ Dart মডেল ক্লাস প্রতিটি কী-এর জন্য final ফিল্ড, নামযুক্ত প্যারামিটারসহ একটি কনস্ট্রাক্টর (non-nullable ফিল্ডের জন্য required কীওয়ার্ড সহ), Map<String, dynamic> থেকে পড়া fromJson নামের একটি ফ্যাক্টরি কনস্ট্রাক্টর এবং Map<String, dynamic> রিটার্ন করা একটি toJson মেথড ঘোষণা করে। নেস্টেড JSON অবজেক্টগুলো পৃথক ক্লাস হয়। অ্যারেগুলো টাইপড List ফিল্ড হয়। Nullable JSON মানগুলো টাইপে ? প্রত্যয় সহ Dart-এর null-safety সিনট্যাক্স ব্যবহার করে।
এই মডেল ক্লাসগুলো হাতে লেখার মানে হলো প্রতিটি JSON কী পড়া, Dart টাইপ নির্ধারণ করা, প্রতিটি ফিল্ডের জন্য fromJson কাস্ট তৈরি করা (.map().toList() দিয়ে লিস্ট ম্যাপিং সহ), একটি toJson ম্যাপ লিটারেল তৈরি করা এবং প্রতিটি নেস্টেড অবজেক্টের জন্য এটি পুনরাবৃত্তি করা। ১২টি ফিল্ড ও ২টি নেস্টেড অবজেক্টসহ একটি JSON অবজেক্টের জন্য এর মানে হলো ৩টি ক্লাস, ৬টি ফ্যাক্টরি লাইন এবং ডজন ডজন কাস্ট এক্সপ্রেশন। একটি কনভার্টার একটিমাত্র পেস্ট থেকে মিলিসেকেন্ডে এই সব তৈরি করে।
কেন JSON থেকে Dart কনভার্টার ব্যবহার করবেন?
JSON থেকে Dart মডেল ক্লাস হাতে লেখার সময় ফিল্ড নাম পড়া, নমুনা মান থেকে টাইপ অনুমান করা, সঠিক null হ্যান্ডলিংসহ fromJson কাস্ট লেখা এবং নেস্টেড অবজেক্টের জন্য প্রক্রিয়াটি পুনরাবৃত্তি করতে হয়। API-এর আকার পরিবর্তিত হলে প্রতিটি ফিল্ড, কনস্ট্রাক্টর, fromJson এবং toJson আপডেট করতে হয়। একটি কনভার্টার সেই পুনরাবৃত্তিমূলক কাজ দূর করে।
JSON থেকে Dart ব্যবহারের ক্ষেত্র
JSON থেকে Dart টাইপ ম্যাপিং
প্রতিটি JSON মান একটি নির্দিষ্ট Dart টাইপে ম্যাপ হয়। নিচের সারণি দেখায় কনভার্টার প্রতিটি JSON টাইপ কীভাবে অনুবাদ করে। বিকল্প কলামে কম সাধারণ বা ম্যানুয়াল ম্যাপিং পরিস্থিতিতে ব্যবহৃত টাইপ দেখানো হয়েছে।
| JSON টাইপ | উদাহরণ | Dart টাইপ | বিকল্প |
|---|---|---|---|
| string | "hello" | String | String |
| number (integer) | 42 | int | int |
| number (float) | 3.14 | double | double |
| boolean | true | bool | bool |
| null | null | dynamic | Null / dynamic |
| object | {"k": "v"} | NestedClass | Map<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 সিরিয়ালাইজেশন পদ্ধতি
Dart ও Flutter JSON সিরিয়ালাইজেশন পরিচালনার একাধিক উপায় প্রদান করে। ম্যানুয়াল fromJson/toJson সবচেয়ে সরল পদ্ধতি এবং কোনো কোড জেনারেশনের প্রয়োজন নেই। বড় প্রকল্পের জন্য, json_serializable ও freezed-এর মতো build_runner-ভিত্তিক সমাধান কম্পাইল সময়ে বয়লারপ্লেট তৈরি করে, ত্রুটি কমায় এবং মডেলগুলো JSON চুক্তির সাথে সামঞ্জস্যপূর্ণ রাখে।
| পদ্ধতি | বিবরণ | উৎস |
|---|---|---|
| json_serializable | Code-generation-based JSON serialization. Generates .g.dart files at build time via build_runner. Type-safe and compile-time verified. | Official (Google) |
| freezed | Generates immutable data classes with copyWith, fromJson/toJson, equality, and pattern matching support. Built on top of json_serializable. | Community (rrousselGit) |
| built_value | Generates immutable value types with serialization. Enforces immutability patterns. Used in larger codebases with strict data modeling. | |
| dart_mappable | Annotation-based mapper that generates fromJson, toJson, copyWith, and equality. Simpler setup than freezed with similar features. | Community |
| Manual fromJson/toJson | Hand-written factory constructors and toJson methods. No code generation needed. Full control over the mapping logic. | Built-in Dart |
Manual বনাম json_serializable বনাম freezed
JSON মডেল ক্লাসের জন্য Dart-এ তিনটি সাধারণ পদ্ধতি আছে। ম্যানুয়াল fromJson/toJson-এর কোনো নির্ভরতা নেই। json_serializable ম্যাপিং কোড স্বয়ংক্রিয় করে। freezed json_serializable-এর উপরে অপরিবর্তনীয়তা, copyWith এবং প্যাটার্ন ম্যাচিং যোগ করে।
কোড উদাহরণ
এই উদাহরণগুলো দেখায় কীভাবে JSON ডিসিরিয়ালাইজেশনের জন্য তৈরি Dart ক্লাস ব্যবহার করতে হয়, build_runner-এর সাথে json_serializable কীভাবে সেটআপ করতে হয় এবং JavaScript ও Python থেকে প্রোগ্রাম্যাটিক্যালি Dart ক্লাস কীভাবে তৈরি করতে হয়।
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
}// 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-outputsfunction 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;
// }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;
# }