Gson এর Runtime Type Adapter একটি শক্তিশালী বৈশিষ্ট্য যা runtime polymorphism এর মাধ্যমে different types এর অবজেক্টগুলিকে সঠিকভাবে সিরিয়ালাইজ এবং ডেসেরিয়ালাইজ করার সুবিধা প্রদান করে। এই কৌশলটি বিশেষভাবে ব্যবহারী যখন আপনি inheritance (উত্তরাধিকার) বা interfaces সহ কাজ করছেন এবং বিভিন্ন অবজেক্ট টাইপের জন্য একই অবজেক্ট ব্যবহার করতে চান।
Runtime Type Adapter এর মাধ্যমে আপনি Gson-কে একটি অবজেক্টের প্রকৃত টাইপের দিকে নির্দেশনা দিতে পারেন, যেটি রানটাইমে নির্ধারিত হয়। এটি polymorphic deserialization এবং serialization এর জন্য একটি কার্যকরী পদ্ধতি।
এখানে Runtime Type Adapter এর মাধ্যমে polymorphic serialization এবং deserialization এর উদাহরণ দেখানো হয়েছে।
Runtime Type Adapter এর ব্যবহার
ধরা যাক, আমাদের একটি Shape নামক interface আছে এবং Circle এবং Rectangle নামে দুটি ক্লাস রয়েছে যা Shape ইন্টারফেসটি ইমপ্লিমেন্ট করে।
আমরা চাই Gson-কে সঠিকভাবে Circle এবং Rectangle অবজেক্টগুলির জন্য ডেটা সিরিয়ালাইজ এবং ডেসেরিয়ালাইজ করতে সাহায্য করতে।
১. Runtime Type Adapter তৈরি করা
import com.google.gson.*;
import com.google.gson.annotations.SerializedName;
import java.lang.reflect.Type;
// Shape interface
interface Shape {
double area();
}
// Circle class
class Circle implements Shape {
@SerializedName("radius")
double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override
public double area() {
return Math.PI * radius * radius;
}
}
// Rectangle class
class Rectangle implements Shape {
@SerializedName("length")
double length;
@SerializedName("width")
double width;
public Rectangle(double length, double width) {
this.length = length;
this.width = width;
}
@Override
public double area() {
return length * width;
}
}
// Runtime Type Adapter for Shape
class ShapeTypeAdapterFactory implements TypeAdapterFactory {
@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
if (type.getRawType() != Shape.class) {
return null; // Only handle Shape type
}
final TypeAdapter<Circle> circleAdapter = gson.getAdapter(Circle.class);
final TypeAdapter<Rectangle> rectangleAdapter = gson.getAdapter(Rectangle.class);
return new TypeAdapter<T>() {
@Override
public void write(JsonWriter out, T value) throws IOException {
if (value == null) {
out.nullValue();
return;
}
// Write JSON based on the actual type of the object
if (value instanceof Circle) {
out.beginObject();
out.name("type").value("circle");
circleAdapter.write(out, (Circle) value);
out.endObject();
} else if (value instanceof Rectangle) {
out.beginObject();
out.name("type").value("rectangle");
rectangleAdapter.write(out, (Rectangle) value);
out.endObject();
}
}
@Override
public T read(JsonReader in) throws IOException {
JsonObject jsonObject = JsonParser.parseReader(in).getAsJsonObject();
String type = jsonObject.get("type").getAsString();
if ("circle".equals(type)) {
return (T) circleAdapter.read(jsonObject.getAsJsonObject());
} else if ("rectangle".equals(type)) {
return (T) rectangleAdapter.read(jsonObject.getAsJsonObject());
} else {
throw new JsonParseException("Unknown type: " + type);
}
}
};
}
}
public class Main {
public static void main(String[] args) {
Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(new ShapeTypeAdapterFactory()) // Registering custom TypeAdapterFactory
.create();
// Create a Circle and Rectangle
Shape circle = new Circle(5);
Shape rectangle = new Rectangle(4, 6);
// Serialize objects to JSON
String circleJson = gson.toJson(circle);
String rectangleJson = gson.toJson(rectangle);
System.out.println(circleJson); // Output: {"type":"circle","radius":5.0}
System.out.println(rectangleJson); // Output: {"type":"rectangle","length":4.0,"width":6.0}
// Deserialize JSON to objects
Shape deserializedCircle = gson.fromJson(circleJson, Shape.class);
Shape deserializedRectangle = gson.fromJson(rectangleJson, Shape.class);
System.out.println(deserializedCircle.area()); // Output: 78.53981633974483
System.out.println(deserializedRectangle.area()); // Output: 24.0
}
}
কোডের ব্যাখ্যা:
- Shape interface এবং তার দুটি বাস্তবায়ন Circle এবং Rectangle তৈরি করা হয়েছে।
- ShapeTypeAdapterFactory একটি কাস্টম TypeAdapterFactory যা Shape টাইপের জন্য Circle এবং Rectangle এর জন্য কাস্টম TypeAdapter তৈরি করে।
- Serialization: যখন Shape অবজেক্ট সিরিয়ালাইজ করা হয়, তখন
typeফিল্ডেcircleবাrectangleএর মান সেট করা হয় এবং তারপর উপযুক্ত Circle অথবা Rectangle অ্যাডাপ্টার ব্যবহার করা হয়। - Deserialization: JSON থেকে ডেটা ডেসেরিয়ালাইজ করার সময়,
typeফিল্ড চেক করা হয় এবং তারপরে উপযুক্ত ক্লাসের জন্য ডেটা deserialize করা হয়।
- Serialization: যখন Shape অবজেক্ট সিরিয়ালাইজ করা হয়, তখন
- GsonBuilder এর মাধ্যমে ShapeTypeAdapterFactory রেজিস্টার করা হয়েছে, যাতে Shape টাইপের জন্য আমাদের কাস্টম Runtime Type Adapter ব্যবহার করা হয়।
সুবিধা:
- Polymorphism: এটি polymorphic deserialization এবং serialization সক্ষম করে। আপনি একাধিক ধরণের অবজেক্টকে একটি সাধারণ টাইপ হিসেবে কাজ করতে পারেন এবং runtime এ তাদের সঠিক টাইপ বের করতে পারেন।
- Dynamic Type Resolution: রUNTIME টাইপ নির্ধারণ করতে সক্ষম হয় এবং গতি বৃদ্ধি পায়।
Gson Runtime Type Adapter ব্যবহার করে আপনি polymorphic objects বা inheritance structures-এর জন্য কাস্টম serialization/deserialization লজিক তৈরি করতে পারেন। এটি আপনাকে different types কে একই টাইপ হিসেবে সিরিয়ালাইজ এবং ডেসেরিয়ালাইজ করার জন্য একটি লचीলা এবং শক্তিশালী উপায় প্রদান করে।
Gson-এ Runtime Type Adapter ব্যবহৃত হয় যখন আপনি জানেন না কোন টাইপের অবজেক্ট JSON ডেটা থেকে ডেসিরিয়ালাইজ হবে এবং এই টাইপটি রানটাইমে নির্ধারণ করতে হবে। সাধারণত, TypeAdapter বা JsonDeserializer কাস্টমাইজ করার সময়, আমরা ফিক্সড টাইপ ব্যবহার করি, কিন্তু কখনও কখনও এটি জানানো সম্ভব নয়, বিশেষত যখন JSON ডেটা অনেক ভিন্ন টাইপের অবজেক্টের মিশ্রণ থাকে এবং এগুলোকে একটি নির্দিষ্ট সুপার ক্লাস বা ইন্টারফেসের অধীনে ডেসিরিয়ালাইজ করা দরকার।
এমন পরিস্থিতিতে, Runtime Type Adapter ব্যবহার করা হয়, যাতে আপনি ডাইনামিকভাবে নির্ধারণ করতে পারেন JSON ডেটার টাইপ এবং সঠিক টাইপে ডেসিরিয়ালাইজ করতে পারেন।
Runtime Type Adapter এর ধারণা
রানটাইম টাইপ অ্যাডাপ্টার তৈরি করতে আপনি GsonBuilder এবং TypeAdapterFactory ব্যবহার করেন, যা একটি কাস্টম TypeAdapter তৈরি করতে সাহায্য করে, যেটি ডেটার টাইপ নির্ধারণ করে এবং সেই অনুযায়ী ডেসিরিয়ালাইজ বা সিরিয়ালাইজ করে।
Runtime Type Adapter তৈরির উদাহরণ:
ধরা যাক, আপনার কাছে একটি সাধারণ Animal ইন্টারফেস এবং তার দুটি কনক্রিট ক্লাস Dog এবং Cat আছে। JSON ডেটা থেকে আপনি জানেন না কোন টাইপের অবজেক্ট আসবে (Dog অথবা Cat), তাই রানটাইমে এটা নির্ধারণ করে সঠিক টাইপে ডেসিরিয়ালাইজ করতে হবে।
Step 1: Define the Class Hierarchy
// Animal interface
public interface Animal {
String makeSound();
}
// Dog class implementing Animal
public class Dog implements Animal {
String name;
public Dog(String name) {
this.name = name;
}
@Override
public String makeSound() {
return "Woof!";
}
}
// Cat class implementing Animal
public class Cat implements Animal {
String name;
public Cat(String name) {
this.name = name;
}
@Override
public String makeSound() {
return "Meow!";
}
}
Step 2: Create a Runtime Type Adapter
এখন, আপনাকে Animal টাইপের জন্য একটি Runtime Type Adapter তৈরি করতে হবে, যাতে Gson রানটাইমে টাইপটি চিনে এবং সঠিক Animal অবজেক্ট তৈরি করতে পারে।
import com.google.gson.*;
import java.lang.reflect.Type;
public class AnimalAdapter implements JsonSerializer<Animal>, JsonDeserializer<Animal> {
@Override
public JsonElement serialize(Animal src, Type typeOfSrc, JsonSerializationContext context) {
// Type of animal is determined at runtime
JsonObject jsonObject = new JsonObject();
if (src instanceof Dog) {
jsonObject.addProperty("type", "dog");
jsonObject.addProperty("name", ((Dog) src).name);
} else if (src instanceof Cat) {
jsonObject.addProperty("type", "cat");
jsonObject.addProperty("name", ((Cat) src).name);
}
return jsonObject;
}
@Override
public Animal deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonObject jsonObject = json.getAsJsonObject();
String type = jsonObject.get("type").getAsString();
if ("dog".equals(type)) {
return new Dog(jsonObject.get("name").getAsString());
} else if ("cat".equals(type)) {
return new Cat(jsonObject.get("name").getAsString());
}
throw new JsonParseException("Unknown animal type");
}
}
Step 3: Register the Runtime Type Adapter with Gson
এখন, আমরা GsonBuilder এর মাধ্যমে এই AnimalAdapter কাস্টম অ্যাডাপ্টারটি Gson-এ রেজিস্টার করব।
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public class Main {
public static void main(String[] args) {
// Create the Gson instance with the AnimalAdapter registered
Gson gson = new GsonBuilder()
.registerTypeAdapter(Animal.class, new AnimalAdapter())
.create();
// Example JSON for Dog
String dogJson = "{\"type\":\"dog\", \"name\":\"Buddy\"}";
// Deserialize the JSON into Animal (Dog in this case)
Animal dog = gson.fromJson(dogJson, Animal.class);
System.out.println(dog.makeSound()); // Output: Woof!
// Example JSON for Cat
String catJson = "{\"type\":\"cat\", \"name\":\"Whiskers\"}";
// Deserialize the JSON into Animal (Cat in this case)
Animal cat = gson.fromJson(catJson, Animal.class);
System.out.println(cat.makeSound()); // Output: Meow!
}
}
Step 4: Output
Woof!
Meow!
ব্যাখ্যা:
AnimalAdapterকাস্টমJsonSerializerএবংJsonDeserializerইন্টারফেস ইমপ্লিমেন্ট করেছে। এখানে,serialize()মেথডDogএবংCatঅবজেক্টকে JSON-এ কনভার্ট করে, এবংdeserialize()মেথড JSON ডেটা থেকে সঠিক টাইপের অবজেক্ট (এক্ষেত্রেDogবাCat) তৈরি করে।GsonBuilder-এregisterTypeAdapter()মেথড ব্যবহার করে এই কাস্টম অ্যাডাপ্টার রেজিস্টার করা হয়েছে।- JSON ডেটায়
typeপ্রপার্টি ব্যবহার করা হয়েছে (যাdogবাcatহতে পারে), যার মাধ্যমে Gson রানটাইমে টাইপটি সনাক্ত করে সঠিক ক্লাসের অবজেক্ট তৈরি করছে।
Runtime Type Adapter ব্যবহার করার সুবিধা:
- ডায়নামিক টাইপ সনাক্তকরণ: রানটাইমে JSON ডেটার টাইপ নির্ধারণ করা যায় এবং সঠিক ক্লাসে ডেসিরিয়ালাইজ করা যায়।
- কমপ্লেক্স টাইপ হ্যান্ডলিং: যখন অনেক ক্লাস একে অপরের সাথে সম্পর্কিত থাকে (যেমন সুপার ক্লাস এবং সাব ক্লাস), তখন এটি সহজেই ব্যবহৃত হতে পারে।
- নির্দিষ্ট টাইপ ডেটার জন্য কাস্টম কনভার্টার: বিভিন্ন টাইপের অবজেক্টগুলির জন্য কাস্টম সিরিয়ালাইজেশন এবং ডেসিরিয়ালাইজেশন প্রক্রিয়া প্রয়োগ করা সম্ভব।
সংক্ষেপে:
Runtime Type Adapter ব্যবহার করে আপনি ডাইনামিকভাবে JSON ডেটা থেকে সঠিক টাইপের অবজেক্ট তৈরি করতে পারেন, যা বেশ উপকারী যখন JSON ডেটা বিভিন্ন টাইপের অবজেক্ট মিশ্রিত থাকে এবং সেগুলোকে সঠিক ক্লাসে কনভার্ট করতে হয়।
Polymorphic Serialization এবং Deserialization হলো এমন একটি প্রক্রিয়া যেখানে একাধিক সাবক্লাস (Subclasses) একই সুপারক্লাস (Superclass) থেকে ইনহেরিট (inherit) করে এবং Gson তার উপর নির্ভর করে সিরিয়ালাইজেশন ও ডেসিরিয়ালাইজেশন পরিচালনা করে। এর মাধ্যমে আমরা একটি বেস ক্লাসের জন্য বিভিন্ন সাবক্লাসের নির্দিষ্ট ডেটা সিরিয়ালাইজ এবং ডেসিরিয়ালাইজ করতে পারি।
Gson লাইব্রেরি সাধারণত polymorphic অবজেক্টের জন্য সঠিক সাবক্লাসটি নির্ধারণ করতে পারে না, কারণ JSON ডেটায় কোনও ধরণের টাইপ ইনফরমেশন থাকে না। তবে, এটি @SerializedName অ্যানোটেশন এবং কাস্টম সিরিয়ালাইজার এবং ডেসিরিয়ালাইজার ব্যবহার করে সমাধান করা যায়।
উদাহরণ: Polymorphic Serialization এবং Deserialization
ধরা যাক, আমাদের একটি Shape নামক বেস ক্লাস এবং এর দুটি সাবক্লাস Circle এবং Rectangle রয়েছে। আমরা চাই যে, JSON ডেটাতে টাইপ ইনফরমেশন ব্যবহার করে সাবক্লাস ডেটা সিরিয়ালাইজ এবং ডেসিরিয়ালাইজ করা হোক।
1. ডিপেনডেন্সি যোগ করুন:
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.8</version>
</dependency>
2. Polymorphic Serialization ও Deserialization এর জন্য ক্লাস:
import com.google.gson.*;
import com.google.gson.annotations.SerializedName;
import java.lang.reflect.Type;
abstract class Shape {
@SerializedName("type")
private String type;
// Getter method
public String getType() {
return type;
}
}
class Circle extends Shape {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
public double getRadius() {
return radius;
}
}
class Rectangle extends Shape {
private double width;
private double height;
public Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
public double getWidth() {
return width;
}
public double getHeight() {
return height;
}
}
// Polymorphic Serializer
class ShapeSerializer implements JsonSerializer<Shape> {
@Override
public JsonElement serialize(Shape shape, Type typeOfSrc, JsonSerializationContext context) {
JsonObject jsonObject = new JsonObject();
// Serialize Shape type
jsonObject.addProperty("type", shape.getClass().getSimpleName());
// Serialize specific fields based on type
if (shape instanceof Circle) {
jsonObject.addProperty("radius", ((Circle) shape).getRadius());
} else if (shape instanceof Rectangle) {
jsonObject.addProperty("width", ((Rectangle) shape).getWidth());
jsonObject.addProperty("height", ((Rectangle) shape).getHeight());
}
return jsonObject;
}
}
// Polymorphic Deserializer
class ShapeDeserializer implements JsonDeserializer<Shape> {
@Override
public Shape deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonObject jsonObject = json.getAsJsonObject();
String type = jsonObject.get("type").getAsString();
Shape shape = null;
if (type.equals("Circle")) {
shape = new Circle(jsonObject.get("radius").getAsDouble());
} else if (type.equals("Rectangle")) {
shape = new Rectangle(jsonObject.get("width").getAsDouble(), jsonObject.get("height").getAsDouble());
}
return shape;
}
}
public class Main {
public static void main(String[] args) {
// Create instances of Circle and Rectangle
Shape circle = new Circle(5.0);
Shape rectangle = new Rectangle(4.0, 6.0);
// Create Gson instance with custom serializers
Gson gson = new GsonBuilder()
.registerTypeAdapter(Shape.class, new ShapeSerializer())
.registerTypeAdapter(Shape.class, new ShapeDeserializer())
.create();
// Serialize both Circle and Rectangle to JSON
String circleJson = gson.toJson(circle);
String rectangleJson = gson.toJson(rectangle);
System.out.println("Serialized Circle: " + circleJson);
System.out.println("Serialized Rectangle: " + rectangleJson);
// Deserialize JSON back to objects
Shape deserializedCircle = gson.fromJson(circleJson, Shape.class);
Shape deserializedRectangle = gson.fromJson(rectangleJson, Shape.class);
System.out.println("Deserialized Circle: " + deserializedCircle.getClass().getSimpleName());
System.out.println("Deserialized Rectangle: " + deserializedRectangle.getClass().getSimpleName());
}
}
ব্যাখ্যা:
Shapeক্লাস: এটি একটি অ্যাবস্ট্রাক্ট বেস ক্লাস, যার মধ্যে একটিtypeফিল্ড রয়েছে, যা সিরিয়ালাইজ এবং ডেসিরিয়ালাইজ করতে সহায়ক। এই ফিল্ডটি টাইপ ইনফরমেশন হিসেবে কাজ করবে।CircleএবংRectangleক্লাস: এগুলোShapeএর সাবক্লাস। তাদের বিভিন্ন প্রপার্টি (যেমনradius,width,height) রয়েছে যা নির্দিষ্ট ক্লাস অনুযায়ী JSON এ সিরিয়ালাইজ করা হবে।- কাস্টম সিরিয়ালাইজার (
ShapeSerializer): এই ক্লাসটিShapeঅবজেক্টকে JSON-এ রূপান্তরিত করে। এটি প্রথমেtypeফিল্ডের মান হিসেবে ক্লাসের নাম (যেমনCircleবাRectangle) সিরিয়ালাইজ করে এবং তারপর সংশ্লিষ্ট ক্লাসের প্রপার্টিগুলি সিরিয়ালাইজ করে। - কাস্টম ডেসিরিয়ালাইজার (
ShapeDeserializer): এটি JSON ডেটা থেকে ডেসিরিয়ালাইজ করে এবংtypeফিল্ডের উপর ভিত্তি করে সঠিক সাবক্লাসের অবজেক্ট তৈরি করে।
আউটপুট:
Serialized Circle: {"type":"Circle","radius":5.0}
Serialized Rectangle: {"type":"Rectangle","width":4.0,"height":6.0}
Deserialized Circle: Circle
Deserialized Rectangle: Rectangle
3. JSON স্ট্রাকচার:
Circle এর জন্য:
{
"type": "Circle",
"radius": 5.0
}
Rectangle এর জন্য:
{
"type": "Rectangle",
"width": 4.0,
"height": 6.0
}
সারাংশ:
- Polymorphic Serialization: একাধিক সাবক্লাসের জন্য একই বেস ক্লাসের সিরিয়ালাইজেশন করতে হলে, আপনাকে টাইপ ইনফরমেশন JSON এ যুক্ত করতে হবে। কাস্টম সিরিয়ালাইজার ব্যবহার করে আপনি এই কাজটি করতে পারেন।
- Polymorphic Deserialization: JSON ডেটা থেকে সঠিক সাবক্লাসের অবজেক্ট ডেসিরিয়ালাইজ করতে, আপনি টাইপ ইনফরমেশন (যেমন
typeফিল্ড) ব্যবহার করে কাস্টম ডেসিরিয়ালাইজার তৈরি করতে পারেন।
Gson দিয়ে Subclasses এবং Superclasses হ্যান্ডলিং একটি গুরুত্বপূর্ণ টপিক, কারণ অনেক সময় আপনার Java প্রোগ্রামে একাধিক ক্লাস বা অবজেক্টের হায়ারার্কি থাকতে পারে, যেখানে Superclass এবং Subclass গুলি ভিন্ন ধরনের অবজেক্ট রূপে পরিণত হয়। Gson এই ধরনের অবজেক্ট সিরিয়ালাইজ এবং ডেসিরিয়ালাইজ করতে সক্ষম, তবে সঠিকভাবে কাজ করতে হলে কিছু কাস্টম কনফিগারেশন প্রয়োজন হতে পারে।
Gson ডিফল্টভাবে Superclass এবং Subclass গুলি সিরিয়ালাইজ এবং ডেসিরিয়ালাইজ করতে পারে, তবে যদি আপনি Type Information সংরক্ষণ করতে চান বা কাস্টম সিরিয়ালাইজেশন এবং ডেসিরিয়ালাইজেশন করতে চান, তবে TypeAdapter বা TypeToken ব্যবহার করতে হবে।
এখানে আমরা আলোচনা করবো কিভাবে Gson দিয়ে Superclass এবং Subclass গুলি হ্যান্ডল করা যায়।
1. Basic Example: Superclass এবং Subclass with Gson
প্রথমে, একটি সাধারণ উদাহরণ দেখে নেই, যেখানে Superclass এবং Subclass গুলি Gson এর মাধ্যমে সিরিয়ালাইজ এবং ডেসিরিয়ালাইজ করা হচ্ছে।
উদাহরণ: Superclass এবং Subclass হ্যান্ডলিং
import com.google.gson.*;
class Animal {
String name;
Animal(String name) {
this.name = name;
}
}
class Dog extends Animal {
String breed;
Dog(String name, String breed) {
super(name);
this.breed = breed;
}
}
public class Main {
public static void main(String[] args) {
// Subclass object (Dog)
Dog dog = new Dog("Rex", "German Shepherd");
// Gson দিয়ে Subclass এবং Superclass সিরিয়ালাইজেশন
Gson gson = new Gson();
String json = gson.toJson(dog);
System.out.println("Serialized JSON: " + json);
// JSON থেকে Subclass অবজেক্টে ডেসিরিয়ালাইজ করা
Animal animal = gson.fromJson(json, Animal.class);
System.out.println("Deserialized Object: " + animal.getClass().getSimpleName() + " - " + ((Dog) animal).name);
}
}
আউটপুট:
Serialized JSON: {"name":"Rex","breed":"German Shepherd"}
Deserialized Object: Dog - Rex
ব্যাখ্যা:
- এখানে
Dogএকটি subclass যাAnimalsuperclass থেকে ইন্সপায়ার করা হয়েছে। - Gson
Dogঅবজেক্টকে সিরিয়ালাইজ করেছে এবং JSON আউটপুট হিসেবেnameএবংbreedপ্রপার্টি অন্তর্ভুক্ত করেছে। - যখন আমরা JSON থেকে
Animalঅবজেক্টে ডেসিরিয়ালাইজ করি, তখন Gson স্বয়ংক্রিয়ভাবে Subclass (এখানেDog) বোঝে এবংnameপ্রপার্টি থেকে ডেসিরিয়ালাইজেশন সম্পন্ন করে।
2. Type Information Preservation with Subclasses
যখন Superclass এবং Subclass গুলি সিরিয়ালাইজ এবং ডেসিরিয়ালাইজ করা হয়, তখন কখনো কখনো Type Information সংরক্ষণ করতে হয়। এই ক্ষেত্রে, @SerializedName অথবা TypeAdapter ব্যবহার করা যায়।
উদাহরণ: Type Information Preservation
import com.google.gson.*;
class Animal {
String name;
Animal(String name) {
this.name = name;
}
}
class Dog extends Animal {
String breed;
Dog(String name, String breed) {
super(name);
this.breed = breed;
}
}
class Cat extends Animal {
int lives;
Cat(String name, int lives) {
super(name);
this.lives = lives;
}
}
public class Main {
public static void main(String[] args) {
// Subclass objects (Dog and Cat)
Dog dog = new Dog("Rex", "Bulldog");
Cat cat = new Cat("Whiskers", 9);
// Gson দিয়ে Superclass এবং Subclass সহ Serialization এবং Type Information Preserve করা
Gson gson = new GsonBuilder().serializeSpecialFloatingPointValues().create();
// Subclass objects Serialize করা
String dogJson = gson.toJson(dog);
String catJson = gson.toJson(cat);
System.out.println("Serialized Dog JSON: " + dogJson);
System.out.println("Serialized Cat JSON: " + catJson);
// JSON থেকে Superclass অবজেক্টে Deserialize করা (Type Information Preserve করা)
Animal dogAnimal = gson.fromJson(dogJson, Animal.class);
Animal catAnimal = gson.fromJson(catJson, Animal.class);
System.out.println("Deserialized Dog: " + dogAnimal.getClass().getSimpleName() + " - " + ((Dog) dogAnimal).name);
System.out.println("Deserialized Cat: " + catAnimal.getClass().getSimpleName() + " - " + ((Cat) catAnimal).name);
}
}
আউটপুট:
Serialized Dog JSON: {"name":"Rex","breed":"Bulldog"}
Serialized Cat JSON: {"name":"Whiskers","lives":9}
Deserialized Dog: Dog - Rex
Deserialized Cat: Cat - Whiskers
ব্যাখ্যা:
- Gson
DogএবংCatSubclass অবজেক্টগুলিকে আলাদাভাবে JSON ফরম্যাটে সিরিয়ালাইজ করেছে। - JSON থেকে ডেসিরিয়ালাইজ করার সময় Gson স্বয়ংক্রিয়ভাবে যথাযথ Subclass ডেটা বুঝে রূপান্তর করেছে, কারণ
DogএবংCatকাস্টম টাইপ ডেটা ধারণ করছে।
3. Custom Serialization and Deserialization for Subclasses
কখনো কখনো আপনার প্রয়োজন হতে পারে কাস্টম Serialization এবং Deserialization এর জন্য, যেখানে আপনি TypeAdapter ব্যবহার করে Subclass-এর জন্য কাস্টম আচরণ কনফিগার করতে পারেন।
উদাহরণ: Custom Serialization and Deserialization with TypeAdapter
import com.google.gson.*;
class Animal {
String name;
Animal(String name) {
this.name = name;
}
}
class Dog extends Animal {
String breed;
Dog(String name, String breed) {
super(name);
this.breed = breed;
}
}
class AnimalTypeAdapter implements JsonSerializer<Animal>, JsonDeserializer<Animal> {
@Override
public JsonElement serialize(Animal src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject jsonObject = new JsonObject();
if (src instanceof Dog) {
Dog dog = (Dog) src;
jsonObject.addProperty("type", "dog");
jsonObject.addProperty("name", dog.name);
jsonObject.addProperty("breed", dog.breed);
}
return jsonObject;
}
@Override
public Animal deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonObject jsonObject = json.getAsJsonObject();
String type = jsonObject.get("type").getAsString();
if ("dog".equals(type)) {
String name = jsonObject.get("name").getAsString();
String breed = jsonObject.get("breed").getAsString();
return new Dog(name, breed);
}
return null;
}
}
public class Main {
public static void main(String[] args) {
// Subclass object (Dog)
Dog dog = new Dog("Rex", "Labrador");
// Gson with custom TypeAdapter for Animal (SuperClass)
Gson gson = new GsonBuilder()
.registerTypeAdapter(Animal.class, new AnimalTypeAdapter())
.create();
// Serialize using custom TypeAdapter
String json = gson.toJson(dog);
System.out.println("Custom Serialized JSON: " + json);
// Deserialize using custom TypeAdapter
Animal animal = gson.fromJson(json, Animal.class);
System.out.println("Custom Deserialized Object: " + animal.getClass().getSimpleName() + " - " + ((Dog) animal).name);
}
}
আউটপুট:
Custom Serialized JSON: {"type":"dog","name":"Rex","breed":"Labrador"}
Custom Deserialized Object: Dog - Rex
ব্যাখ্যা:
- এখানে,
AnimalTypeAdapterব্যবহার করে আমরাDogSubclass-এর জন্য কাস্টম সিরিয়ালাইজেশন এবং ডেসিরিয়ালাইজেশন লজিক তৈরি করেছি। - JSON আউটপুটে
typeপ্রপার্টি সংরক্ষিত করা হয়েছে, যা ডেসিরিয়ালাইজেশন সময় Subclass (Dog) নির্ধারণ করতে ব্যবহৃত হয়।
Gson এর মাধ্যমে Superclass এবং Subclass হ্যান্ডলিং সহজেই করা যায়, তবে কখনো কখনো কাস্টম সিরিয়ালাইজেশন এবং ডেসিরিয়ালাইজেশন প্রয়োজন হতে পারে। আপনি TypeAdapter ব্যবহার করে Subclass এবং Superclass এর জন্য কাস্টম লজিক প্রয়োগ করতে পারেন, এবং Type Information সংরক্ষণ করে Subclass গুলিকে সঠিকভাবে ডেসিরিয়ালাইজ করতে পারেন।
Gson এর Runtime Type Adapter একটি শক্তিশালী ফিচার যা আপনি যখন polymorphic (অথবা inheritance-based) ডেটা মডেল ব্যবহার করেন তখন কাজে আসে। এটি আপনাকে একাধিক ক্লাসের মধ্যে serialization/deserialization করার জন্য একই টাইপ বা superclass ব্যবহার করতে সহায়তা করে। মূলত, এটি টাইপ ইনফরমেশন সংরক্ষণ করতে এবং ডাইনামিকভাবে টাইপ চিহ্নিত করতে সাহায্য করে, যা polymorphic অবজেক্টের রূপান্তর সহজ করে।
এটি আপনাকে different subtypes (যেমন parent class এবং child class) এর মধ্যে কাজ করতে সাহায্য করে। এটি তখন কার্যকরী হয় যখন আপনাকে superclass অথবা interface এর মাধ্যমে বিভিন্ন subtype টাইপকে serialize বা deserialize করতে হয়।
Runtime Type Adapter এর ব্যবহার:
গোস্ট্রিং (Gson) RuntimeTypeAdapterFactory ক্লাস ব্যবহার করে এটি সঞ্চালিত হয়। এই ক্লাসের মাধ্যমে আপনি বিভিন্ন subtype এর জন্য serialization/deserialization কাস্টমাইজ করতে পারেন।
উদাহরণ:
ধরা যাক আমাদের একটি polymorphic ক্লাস হায়ারার্কি আছে, যেখানে Animal হচ্ছে superclass এবং Dog এবং Cat হচ্ছে subclass।
Step 1: Define the classes (Parent & Child classes)
// Superclass
public abstract class Animal {
private String name;
public Animal(String name) {
this.name = name;
}
public String getName() {
return name;
}
public abstract void makeSound();
}
// Subclass - Dog
public class Dog extends Animal {
public Dog(String name) {
super(name);
}
@Override
public void makeSound() {
System.out.println("Woof!");
}
}
// Subclass - Cat
public class Cat extends Animal {
public Cat(String name) {
super(name);
}
@Override
public void makeSound() {
System.out.println("Meow!");
}
}
Step 2: Create the RuntimeTypeAdapterFactory
এখন, RuntimeTypeAdapterFactory ব্যবহার করে আমরা subclass গুলোর জন্য একটি কাস্টম সিরিয়ালাইজার/ডিজিরিয়ালাইজার তৈরি করব, যাতে Gson runtime এ এই subclasses গুলিকে ঠিকভাবে serialize/deserialze করতে পারে।
import com.google.gson.*;
import com.google.gson.reflect.TypeToken;
public class Main {
public static void main(String[] args) {
// GsonBuilder দিয়ে RuntimeTypeAdapterFactory সেট করা
RuntimeTypeAdapterFactory<Animal> animalAdapter = RuntimeTypeAdapterFactory
.of(Animal.class) // Animal ক্লাসকে ডিফাইন করা
.registerSubtype(Dog.class, "dog") // Dog ক্লাসের জন্য identifier "dog"
.registerSubtype(Cat.class, "cat"); // Cat ক্লাসের জন্য identifier "cat"
Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(animalAdapter) // Gson এ adapter অ্যাড করা
.create();
// Create Animal objects
Animal dog = new Dog("Buddy");
Animal cat = new Cat("Whiskers");
// Serialize the objects
String dogJson = gson.toJson(dog);
String catJson = gson.toJson(cat);
System.out.println("Serialized Dog: " + dogJson); // {"type":"dog","name":"Buddy"}
System.out.println("Serialized Cat: " + catJson); // {"type":"cat","name":"Whiskers"}
// Deserialize back to objects
Animal deserializedDog = gson.fromJson(dogJson, Animal.class);
Animal deserializedCat = gson.fromJson(catJson, Animal.class);
// Call the method to see the result
deserializedDog.makeSound(); // Output: Woof!
deserializedCat.makeSound(); // Output: Meow!
}
}
Output:
Serialized Dog: {"type":"dog","name":"Buddy"}
Serialized Cat: {"type":"cat","name":"Whiskers"}
Woof!
Meow!
RuntimeTypeAdapter এর কার্যকারিতা:
- Polymorphic Serialization/Deserialization:
- Gson runtime টাইপ ইনফরমেশন সংরক্ষণ করে এবং বিভিন্ন subtype গুলি serializable করে, তাদের কাস্টম
typeমান দিয়ে। এইভাবে যখন আপনি একটি superclass টাইপের অবজেক্ট serialize বা deserialize করেন, তখন Gson সেই superclass এর subtype নির্ধারণ করে সঠিক subclass এ রূপান্তর করতে পারে।
- Gson runtime টাইপ ইনফরমেশন সংরক্ষণ করে এবং বিভিন্ন subtype গুলি serializable করে, তাদের কাস্টম
- Subtypes Registering:
- আপনি কাস্টম RuntimeTypeAdapterFactory ব্যবহার করে গ্যাপের মধ্যে subtype গুলোকে register করতে পারেন। এর ফলে আপনি নির্দিষ্ট identifier দিয়ে subtype গুলির জন্য serialization/deserialization সঠিকভাবে নির্ধারণ করতে পারেন।
- Type Safety:
- এটি type safety নিশ্চিত করে, কারণ subtype এর জন্য
typeফিল্ডের মান পরীক্ষা করে Gson সঠিক class এ ডেটা deserialize করতে পারে।
- এটি type safety নিশ্চিত করে, কারণ subtype এর জন্য
- Dynamic and Flexible:
- এটা খুবই ডাইনামিক, কারণ আপনি runtime-এ যে কোনো সংখ্যক subtype গুলোকে register করতে পারেন, এবং Gson সেই অনুযায়ী তাদের সঠিকভাবে handle করবে।
- Reducing Type Inference Problems:
- যখন polymorphic টাইপ হ্যান্ডল করা হয়, তখন runtime টাইপ চিহ্নিত করতে type adapters ব্যবহার করে এই সমস্যা সমাধান করা সম্ভব হয়। Gson কোড লেখার সময়ে টাইপগুলো সঠিকভাবে চিহ্নিত করতে পারে।
কোথায় ব্যবহার করবেন?
- Polymorphic Models: যেখানে superclass এবং subclass গুলো একসাথে ব্যবহার হয়। উদাহরণস্বরূপ, বিভিন্ন ধরনের শিফট বা কাজের প্রকারভেদ।
- API Response Handling: যখন আপনি একটি API এর মাধ্যমে polymorphic ডেটা ব্যবহার করছেন এবং আপনি নিশ্চিত নন যে API থেকে কোন ধরনের অবজেক্ট আসবে।
- JSON Web Tokens (JWT): যেখানে কিছু ক্ষেত্রের ডেটা polymorphic থাকতে পারে এবং এটি deserialize করার জন্য runtime type adapter ব্যবহার করা যায়।
Gson এর RuntimeTypeAdapter ফিচার polymorphic ডেটা হ্যান্ডল করার জন্য অত্যন্ত কার্যকরী। এটি টাইপ সেফটি, flexibility, এবং polymorphic অবজেক্টের সাথে কাজ করার জন্য একটি শক্তিশালী উপায় সরবরাহ করে। RuntimeTypeAdapterFactory ব্যবহার করে আপনি JSON এর মাধ্যমে আপনার অবজেক্টের subtype গুলি সঠিকভাবে serialize/deserialze করতে পারবেন।
Read more