Gson এ Polymorphic Object Handling একটি গুরুত্বপূর্ণ ফিচার যা আপনাকে একাধিক subtypes বা child classes নিয়ে কাজ করতে সহায়তা করে, যখন আপনি একটি superclass বা interface ব্যবহার করে serialization বা deserialization করতে চান। Polymorphism সাধারণত Inheritance এর সাথে সম্পর্কিত, যেখানে একটি superclass বা interface এর মাধ্যমে বিভিন্ন subclass বা implementation হ্যান্ডল করা হয়।
Gson এর Polymorphic Object Handling এর মাধ্যমে আপনি runtime type information ব্যবহার করে polymorphic objects গুলির সঠিক serialization/deserialization করতে পারবেন।
Polymorphic Object হ্যান্ডলিং কিভাবে কাজ করে?
Gson এ polymorphic objects হ্যান্ডল করার জন্য RuntimeTypeAdapterFactory ব্যবহার করা হয়, যা বিভিন্ন subtype গুলির জন্য টাইপ ইনফরমেশন সংরক্ষণ করে এবং এগুলিকে সঠিকভাবে serialize/deserialze করে। এইভাবে আপনি যখন superclass অথবা interface এর মাধ্যমে একটি polymorphic object serialize বা deserialize করতে চান, তখন Gson স্বয়ংক্রিয়ভাবে সঠিক subclass বা implementation নির্বাচন করে।
Polymorphic Object Handling Example:
ধরা যাক আমাদের একটি Shape নামক superclass রয়েছে এবং এর দুটি subclass Circle এবং Rectangle রয়েছে। আমরা Gson দিয়ে এই polymorphic objects গুলিকে JSON এ serialize এবং JSON থেকে deserialize করতে চাই।
Step 1: Define the Classes (Parent and Child classes)
// Superclass
public abstract class Shape {
private String color;
public Shape(String color) {
this.color = color;
}
public String getColor() {
return color;
}
public abstract double area();
}
// Subclass - Circle
public class Circle extends Shape {
private double radius;
public Circle(String color, double radius) {
super(color);
this.radius = radius;
}
@Override
public double area() {
return Math.PI * radius * radius;
}
}
// Subclass - Rectangle
public class Rectangle extends Shape {
private double width;
private double height;
public Rectangle(String color, double width, double height) {
super(color);
this.width = width;
this.height = height;
}
@Override
public double area() {
return width * height;
}
}
Step 2: Create RuntimeTypeAdapterFactory and Gson Configuration
এখন আমরা RuntimeTypeAdapterFactory ব্যবহার করে এই polymorphic objects গুলিকে serialize এবং deserialize করব।
import com.google.gson.*;
import com.google.gson.reflect.TypeToken;
public class Main {
public static void main(String[] args) {
// Create the RuntimeTypeAdapterFactory for Shape class
RuntimeTypeAdapterFactory<Shape> shapeAdapterFactory = RuntimeTypeAdapterFactory
.of(Shape.class) // Define the parent type (Shape)
.registerSubtype(Circle.class, "circle") // Register the Circle subtype
.registerSubtype(Rectangle.class, "rectangle"); // Register the Rectangle subtype
// Create a Gson instance with the RuntimeTypeAdapterFactory
Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(shapeAdapterFactory) // Register the adapter factory
.setPrettyPrinting() // Optionally enable pretty printing
.create();
// Create Shape objects (Circle and Rectangle)
Shape circle = new Circle("Red", 5.0);
Shape rectangle = new Rectangle("Blue", 4.0, 6.0);
// Serialize the objects to JSON
String circleJson = gson.toJson(circle);
String rectangleJson = gson.toJson(rectangle);
// Print the serialized JSON
System.out.println("Serialized Circle: " + circleJson);
System.out.println("Serialized Rectangle: " + rectangleJson);
// Deserialize the JSON back to Shape objects
Shape deserializedCircle = gson.fromJson(circleJson, Shape.class);
Shape deserializedRectangle = gson.fromJson(rectangleJson, Shape.class);
// Output the area of the deserialized objects
System.out.println("Deserialized Circle Area: " + deserializedCircle.area());
System.out.println("Deserialized Rectangle Area: " + deserializedRectangle.area());
}
}
Output:
Serialized Circle: {
"type": "circle",
"color": "Red",
"radius": 5.0
}
Serialized Rectangle: {
"type": "rectangle",
"color": "Blue",
"width": 4.0,
"height": 6.0
}
Deserialized Circle Area: 78.53981633974483
Deserialized Rectangle Area: 24.0
ব্যাখ্যা:
- RuntimeTypeAdapterFactory:
- RuntimeTypeAdapterFactory তৈরি করা হয়েছে যাতে
Shapeক্লাসের সব subtype গুলির জন্য runtime type information সংরক্ষণ করা যায়। এখানেCircleএবংRectangleগুলি সাবটাইপ হিসেবে register করা হয়েছে। circleএবংrectangleসাবটাইপ গুলি JSON এ আলাদা type identifier ("type": "circle"এবং"type": "rectangle") সহ serialize হবে।
- RuntimeTypeAdapterFactory তৈরি করা হয়েছে যাতে
- Serialization:
circleJsonএবংrectangleJsonJSON ফরম্যাটে তৈরি করা হয়েছে, যেখানেtypeফিল্ডের মাধ্যমে subtype গুলোর টাইপ নির্দেশ করা হয়েছে।
- Deserialization:
- JSON থেকে
Shapeটাইপে deserialize করার সময়, Gson সঠিকভাবে subtype নির্ধারণ করতে পারে কারণRuntimeTypeAdapterFactoryএর মাধ্যমে টাইপ ইনফরমেশন সন্নিবেশিত হয়েছে। - এখানে
circleJsonএবংrectangleJsonJSON থেকে যথাক্রমেCircleএবংRectangleঅবজেক্টে রূপান্তরিত হয়েছে।
- JSON থেকে
- Type Safety:
- Polymorphic serialization/deserialization এর মাধ্যমে, আমাদের JSON ডেটা সঠিকভাবে অবজেক্টে রূপান্তরিত হয়েছে এবং আমরা নিশ্চিত হয়েছি যে, সঠিক
Shapesubtype এরarea()method কল হয়েছে।
- Polymorphic serialization/deserialization এর মাধ্যমে, আমাদের JSON ডেটা সঠিকভাবে অবজেক্টে রূপান্তরিত হয়েছে এবং আমরা নিশ্চিত হয়েছি যে, সঠিক
Runtime Type Adapter এর সুবিধা:
- Polymorphic Serialization/Deserialization:
- আপনাকে superclass বা interface ব্যবহার করে polymorphic objects হ্যান্ডল করার জন্য টাইপ ইনফরমেশন সংরক্ষণ করার সুযোগ দেয়।
- Flexible Type Management:
- নতুন subtype যোগ করতে সহজ, কারণ আপনাকে শুধু
RuntimeTypeAdapterFactoryতে subtype গুলো register করতে হবে।
- নতুন subtype যোগ করতে সহজ, কারণ আপনাকে শুধু
- Type Safety:
- runtime type information দিয়ে Gson সঠিক subtype নির্বাচন করতে পারে, ফলে টাইপ মিসম্যাচ হওয়ার ঝুঁকি কমে।
- Dynamic Handling:
- JSON ডেটার মাধ্যমে polymorphic objects কে ডাইনামিকভাবে handle করতে পারে, যেহেতু টাইপ ইনফরমেশন runtime এ প্রসেস করা হয়।
কোথায় ব্যবহার করবেন?
- Polymorphic Models: যেখানে superclass এবং subclass গুলি একসাথে ব্যবহৃত হয়। যেমন, বিভিন্ন ধরনের
Shape(circle, rectangle, triangle) বা অন্যান্য polymorphic structures। - API Response Handling: যখন API থেকে polymorphic JSON ডেটা আসে এবং আপনি জানেন না কোন subtype আসবে।
- Design Patterns: যেমন,
VisitorবাFactorydesign patterns এ polymorphic behavior থাকে।
Gson এর RuntimeTypeAdapter ফিচার polymorphic objects হ্যান্ডলিং এর জন্য একটি শক্তিশালী উপায়। এটি serialization এবং deserialization এর মাধ্যমে বিভিন্ন subtypes কে সঠিকভাবে JSON ফরম্যাটে কনভার্ট করতে সহায়তা করে। RuntimeTypeAdapterFactory ব্যবহার করে আপনি polymorphic ডেটা সহজে manage করতে পারবেন, যা type safety এবং flexibility প্রদান করে।
Polymorphism হলো একটি অবজেক্ট-ওরিয়েন্টেড প্রোগ্রামিং (OOP) এর একটি মৌলিক ধারণা, যেখানে একাধিক শ্রেণী (class) একই ধরনের ইন্টারফেস বা বেস ক্লাস (base class) কে অনুসরণ করে এবং সেই শ্রেণীগুলি ভিন্ন ভিন্ন আচরণ করতে পারে। Gson-এ polymorphic objects ব্যবহৃত হয় যখন আপনার JSON ডেটা একটি বেস ক্লাস বা ইন্টারফেসের মাধ্যমে একাধিক কাস্টম টাইপ (subclass) ধারণ করে, এবং আপনি ঐ ডেটাকে JSON থেকে Java অবজেক্টে রূপান্তর করতে চান।
Polymorphic Objects বা Polymorphism হল এমন অবজেক্ট যেগুলি বিভিন্ন উপ subclass-এ ডাটা রাখে, কিন্তু আপনি এই subclass গুলিকে একই superclass হিসাবে ব্যবহার করতে পারেন। Gson-এ polymorphic object ম্যানিপুলেট করতে হলে, আপনাকে subclass গুলিকে সঠিকভাবে ডেসেরিয়ালাইজ বা সিরিয়ালাইজ করতে হবে।
Polymorphic Object কী?
Polymorphic object এমন একটি অবজেক্ট যা একই বেস ক্লাসের (superclass) মাধ্যমে একাধিক সাবক্লাস (subclass) ধারণ করে। সাধারণত, এই প্রক্রিয়াটি ব্যবহার হয় যখন আপনার JSON ডেটা বেস ক্লাস বা ইন্টারফেসের মাধ্যমে একাধিক subclass নিয়ে কাজ করে।
উদাহরণ হিসেবে, আপনি যদি একাধিক ধরণের গাড়ি (Car) ধারণ করতে চান যেমন Sedan, SUV, এবং Truck, তবে আপনি একটি বেস ক্লাস হিসেবে Car ব্যবহার করতে পারেন এবং প্রতিটি গাড়ির ধরনকে একটি subclass হিসেবে তৈরি করতে পারেন।
Gson-এ Polymorphic Object কেন প্রয়োজন?
- একাধিক সাবক্লাসের মধ্যে সাধারণ আচরণ বজায় রাখা: যখন আপনার একই বেস ক্লাসের মাধ্যমে বিভিন্ন ধরনের অবজেক্টকে ম্যানেজ করতে হয়, তখন polymorphism খুবই উপকারী। Gson-এর মাধ্যমে আপনি JSON ডেটা থেকে একাধিক টাইপকে রূপান্তর করতে পারেন এবং সেগুলিকে একটি সাধারণ টাইপ (বেস ক্লাস) হিসেবে ম্যানিপুলেট করতে পারবেন।
- ডায়নামিক টাইপ সিলেকশন: Polymorphism দিয়ে আপনি একাধিক সাবক্লাসের মধ্যে ডায়নামিক টাইপ সিলেকশন করতে পারেন। এটি তখন ব্যবহৃত হয় যখন আপনি জানেন না JSON ডেটাতে কোন টাইপ থাকবে এবং আপনি সেটি runtime এ সিদ্ধান্ত নিতে চান।
- JSON থেকে অবজেক্টের ধরন সঠিকভাবে রূপান্তর করা: Polymorphic object ব্যবহার করলে JSON ডেটা থেকে বিভিন্ন subtype অবজেক্ট সঠিকভাবে রূপান্তর করা সহজ হয়, বিশেষ করে যখন JSON ডেটা কোনও টাইপ নির্দিষ্ট না করে থাকে (যেমন, একটি
"type"ফিল্ড দিয়ে সাবক্লাসের ধরন নির্ধারণ করা)।
Polymorphic Object Mapping in Gson
Gson-এ polymorphic object ম্যানিপুলেট করার জন্য সাধারণত TypeAdapter বা JsonDeserializer ব্যবহার করা হয়। Gson এর কাস্টম টাইপ অ্যাডাপ্টার এর মাধ্যমে আপনি JSON ডেটার মধ্যে polymorphic objects সঠিকভাবে রূপান্তর করতে পারেন।
Polymorphic Object Mapping Example:
ধরি, আমাদের একটি Vehicle বেস ক্লাস এবং তার কয়েকটি সাবক্লাস আছে।
- বেস ক্লাস (Vehicle) এবং সাবক্লাস (Car, Bike):
abstract class Vehicle {
String brand;
public Vehicle(String brand) {
this.brand = brand;
}
abstract void drive();
}
class Car extends Vehicle {
int doors;
public Car(String brand, int doors) {
super(brand);
this.doors = doors;
}
@Override
void drive() {
System.out.println("Driving a car");
}
}
class Bike extends Vehicle {
boolean hasCarrier;
public Bike(String brand, boolean hasCarrier) {
super(brand);
this.hasCarrier = hasCarrier;
}
@Override
void drive() {
System.out.println("Riding a bike");
}
}
- JSON Example (Polymorphic Data with Type):
{
"type": "car",
"brand": "Toyota",
"doors": 4
}
এখানে, "type" ফিল্ডটি JSON ডেটা থেকে বুঝতে সাহায্য করবে যে এটি একটি Car টাইপের অবজেক্ট।
- Gson-এ Polymorphic Object Mapping (TypeAdapter):
Gson এর TypeAdapter ব্যবহার করে, আপনি polymorphic objects সঠিকভাবে ডেসেরিয়ালাইজ করতে পারেন। নিচে এর উদাহরণ দেখানো হলো:
import com.google.gson.*;
import com.google.gson.reflect.TypeToken;
class VehicleDeserializer implements JsonDeserializer<Vehicle> {
@Override
public Vehicle deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonObject jsonObject = json.getAsJsonObject();
String type = jsonObject.get("type").getAsString();
if ("car".equals(type)) {
return new Gson().fromJson(json, Car.class); // Car object
} else if ("bike".equals(type)) {
return new Gson().fromJson(json, Bike.class); // Bike object
}
return null;
}
}
public class Main {
public static void main(String[] args) {
String json = "{\"type\":\"car\", \"brand\":\"Toyota\", \"doors\":4}";
// Gson with TypeAdapter for polymorphic objects
Gson gson = new GsonBuilder()
.registerTypeAdapter(Vehicle.class, new VehicleDeserializer())
.create();
// Deserialize JSON to Vehicle object (polymorphic)
Vehicle vehicle = gson.fromJson(json, Vehicle.class);
vehicle.drive(); // It will call the Car's drive method
}
}
আউটপুট:
Driving a car
এখানে, VehicleDeserializer ব্যবহার করে JSON ডেটা থেকে সঠিক Car বা Bike অবজেক্ট ডেসেরিয়ালাইজ করা হয়েছে। "type" ফিল্ডের মান দেখে নির্ধারণ করা হয়েছে যে এটি কোন subclass হবে।
Polymorphic Object Mapping using @JsonAdapter (Simpler Approach)
আপনি @JsonAdapter অ্যানোটেশন ব্যবহার করেও একই কাজ করতে পারেন:
@JsonAdapter(VehicleDeserializer.class)
abstract class Vehicle {
String brand;
public Vehicle(String brand) {
this.brand = brand;
}
abstract void drive();
}
এখানে, @JsonAdapter অ্যানোটেশনটি VehicleDeserializer টাইপ অ্যাডাপ্টার ব্যবহার করে polymorphic ডেসেরিয়ালাইজেশন সরাসরি করাতে সাহায্য করবে।
সারাংশ:
- Polymorphic Object হল এমন অবজেক্ট যা একাধিক সাবক্লাস ধারণ করে, এবং JSON ডেটার মধ্যে টাইপ নির্ধারণ করে আপনি ঐ ডেটাকে বিভিন্ন ধরনের অবজেক্টে রূপান্তর করতে পারেন।
- Gson polymorphic objects ডেসেরিয়ালাইজ করতে TypeAdapter অথবা
@JsonAdapterঅ্যানোটেশন ব্যবহার করতে সাহায্য করে। - Polymorphism খুবই উপকারী যখন আপনার JSON ডেটাতে একাধিক টাইপ থাকে এবং আপনি সেগুলোকে বেস ক্লাসের মাধ্যমে পরিচালনা করতে চান।
Polymorphic Serialization এবং Deserialization Gson-এ এমন একটি কনসেপ্ট, যা ইনহেরিটেন্স বা ক্লাস হায়ারার্কি সম্পর্কিত অবজেক্টগুলোর জন্য ব্যবহার করা হয়। এই কনসেপ্টের মাধ্যমে আপনি একাধিক subclass (উপক্লাস) এবং তাদের পারেন্ট ক্লাস (superclass) সম্পর্কিত অবজেক্টগুলিকে JSON-এ সিরিয়ালাইজ এবং ডেসিরিয়ালাইজ করতে পারেন।
যতক্ষণ না আপনি Gson কনফিগারেশন ব্যবহার করে polymorphic (বিভিন্ন রকম) অবজেক্টকে JSON বা Java অবজেক্টে রূপান্তর করবেন, ততক্ষণ পর্যন্ত Gson ডিফল্টভাবে এই ধরনের অবজেক্টের মধ্যে পার্থক্য করতে পারে না। আপনাকে উপযুক্ত কাস্টম TypeAdapter বা JsonDeserializer/JsonSerializer তৈরি করতে হবে।
Polymorphic Serialization এবং Deserialization এর ধারণা:
ধরা যাক, আপনার কাছে একটি বেস ক্লাস Animal এবং এর দুটি সাবক্লাস Dog এবং Cat আছে। আপনাকে এই ক্লাসগুলোর অবজেক্টগুলি JSON-এ সিরিয়ালাইজ এবং ডেসিরিয়ালাইজ করতে হবে, তবে আপনার উদ্দেশ্য হলো যে, JSON স্ট্রিং থেকে Dog এবং Cat অবজেক্টের মধ্যে পার্থক্য করা।
1. Polymorphic Serialization:
এটি এমন একটি প্রক্রিয়া যেখানে superclass এবং subclass অবজেক্টগুলি JSON-এ সিরিয়ালাইজ করা হয়, কিন্তু আপনাকে JSON-এ ক্লাস টাইপ সংরক্ষণ করতে হবে যাতে সিরিয়ালাইজড অবজেক্টটি subtype চিহ্নিত করা যায়।
উদাহরণ:
import com.google.gson.*;
import java.lang.reflect.Type;
// Superclass
class Animal {
String name;
public Animal(String name) {
this.name = name;
}
}
// Subclass 1
class Dog extends Animal {
public Dog(String name) {
super(name);
}
}
// Subclass 2
class Cat extends Animal {
public Cat(String name) {
super(name);
}
}
// Custom Serializer to handle polymorphic serialization
class AnimalSerializer implements JsonSerializer<Animal> {
@Override
public JsonElement serialize(Animal src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("name", src.name);
// Serialize the specific type (Dog or Cat)
if (src instanceof Dog) {
jsonObject.addProperty("type", "Dog");
} else if (src instanceof Cat) {
jsonObject.addProperty("type", "Cat");
}
return jsonObject;
}
}
public class Main {
public static void main(String[] args) {
Animal dog = new Dog("Buddy");
Animal cat = new Cat("Whiskers");
Gson gson = new GsonBuilder()
.registerTypeAdapter(Animal.class, new AnimalSerializer()) // Register custom serializer
.create();
// Serializing the polymorphic objects
String dogJson = gson.toJson(dog);
String catJson = gson.toJson(cat);
System.out.println(dogJson); // {"name":"Buddy","type":"Dog"}
System.out.println(catJson); // {"name":"Whiskers","type":"Cat"}
}
}
আউটপুট:
{"name":"Buddy","type":"Dog"}
{"name":"Whiskers","type":"Cat"}
এখানে Dog এবং Cat অবজেক্টগুলি JSON-এ সিরিয়ালাইজ হচ্ছে, এবং তাদের type নামে একটি নতুন ফিল্ড যোগ করা হচ্ছে, যা তাদের ক্লাস টাইপ সংরক্ষণ করে।
2. Polymorphic Deserialization:
এই প্রক্রিয়ায় JSON ডেটা থেকে subclass বা superclass অবজেক্ট ডেসিরিয়ালাইজ করা হয়, যেখানে subtype চিহ্নিত করার জন্য JSON স্ট্রিংয়ের একটি অংশ ব্যবহার করা হয়।
উদাহরণ:
import com.google.gson.*;
import java.lang.reflect.Type;
// Superclass
class Animal {
String name;
public Animal(String name) {
this.name = name;
}
}
// Subclass 1
class Dog extends Animal {
public Dog(String name) {
super(name);
}
}
// Subclass 2
class Cat extends Animal {
public Cat(String name) {
super(name);
}
}
// Custom Deserializer to handle polymorphic deserialization
class AnimalDeserializer implements JsonDeserializer<Animal> {
@Override
public Animal deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonObject jsonObject = json.getAsJsonObject();
String name = jsonObject.get("name").getAsString();
String type = jsonObject.get("type").getAsString();
if (type.equals("Dog")) {
return new Dog(name);
} else if (type.equals("Cat")) {
return new Cat(name);
} else {
return new Animal(name); // Default case
}
}
}
public class Main {
public static void main(String[] args) {
String dogJson = "{\"name\":\"Buddy\",\"type\":\"Dog\"}";
String catJson = "{\"name\":\"Whiskers\",\"type\":\"Cat\"}";
Gson gson = new GsonBuilder()
.registerTypeAdapter(Animal.class, new AnimalDeserializer()) // Register custom deserializer
.create();
// Deserializing the JSON to respective objects
Animal dog = gson.fromJson(dogJson, Animal.class);
Animal cat = gson.fromJson(catJson, Animal.class);
System.out.println(dog.getClass().getSimpleName() + ": " + dog.name); // Dog: Buddy
System.out.println(cat.getClass().getSimpleName() + ": " + cat.name); // Cat: Whiskers
}
}
আউটপুট:
Dog: Buddy
Cat: Whiskers
এখানে AnimalDeserializer কাস্টম ডেসিরিয়ালাইজার ব্যবহার করা হয়েছে যা JSON-এ থাকা "type" ফিল্ড থেকে ক্লাস টাইপ পঠন করে এবং যথাযথ subtype অবজেক্টে রূপান্তরিত করে।
3. Polymorphic Serialization এবং Deserialization একসাথে ব্যবহার:
এখন, আপনি যদি polymorphic অবজেক্ট সিরিয়ালাইজ এবং ডেসিরিয়ালাইজ করতে চান একই সময়, তাহলে Gson এর serializer এবং deserializer একসাথে ব্যবহার করতে হবে।
import com.google.gson.*;
import java.lang.reflect.Type;
// Superclass
class Animal {
String name;
public Animal(String name) {
this.name = name;
}
}
// Subclass 1
class Dog extends Animal {
public Dog(String name) {
super(name);
}
}
// Subclass 2
class Cat extends Animal {
public Cat(String name) {
super(name);
}
}
// Custom Serializer
class AnimalSerializer implements JsonSerializer<Animal> {
@Override
public JsonElement serialize(Animal src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("name", src.name);
if (src instanceof Dog) {
jsonObject.addProperty("type", "Dog");
} else if (src instanceof Cat) {
jsonObject.addProperty("type", "Cat");
}
return jsonObject;
}
}
// Custom Deserializer
class AnimalDeserializer implements JsonDeserializer<Animal> {
@Override
public Animal deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonObject jsonObject = json.getAsJsonObject();
String name = jsonObject.get("name").getAsString();
String type = jsonObject.get("type").getAsString();
if (type.equals("Dog")) {
return new Dog(name);
} else if (type.equals("Cat")) {
return new Cat(name);
} else {
return new Animal(name);
}
}
}
public class Main {
public static void main(String[] args) {
Animal dog = new Dog("Buddy");
Animal cat = new Cat("Whiskers");
Gson gson = new GsonBuilder()
.registerTypeAdapter(Animal.class, new AnimalSerializer()) // Register custom serializer
.registerTypeAdapter(Animal.class, new AnimalDeserializer()) // Register custom deserializer
.create();
// Serialize the objects
String dogJson = gson.toJson(dog);
String catJson = gson.toJson(cat);
System.out.println(dogJson); // {"name":"Buddy","type":"Dog"}
System.out.println(catJson); // {"name":"Whiskers","type":"Cat"}
// Deserialize back to objects
Animal deserializedDog = gson.fromJson(dogJson, Animal.class);
Animal deserializedCat = gson.fromJson(catJson, Animal.class);
System.out.println(deserializedDog.getClass().getSimpleName() + ": " + deserializedDog.name);
System.out.println(deserializedCat.getClass().getSimpleName() + ": " + deserializedCat.name);
}
}
আউটপুট:
{"name":"Buddy","type":"Dog"}
{"name":"Whiskers","type":"Cat"}
Dog: Buddy
Cat: Whiskers
এখানে polymorphic serialization এবং deserialization একসাথে কাজ করছে, যেখানে আমরা custom serializer এবং custom deserializer ব্যবহার করেছি।
সারসংক্ষেপ:
- Polymorphic Serialization:
JsonSerializerব্যবহার করেsuperclassএবংsubclassঅবজেক্টগুলোকে JSON-এ সিরিয়ালাইজ করা হয়, এবং তাদের টাইপের জন্য একটি অতিরিক্ত ফিল্ড (যেমন"type") ব্যবহার করা হয়। - Polymorphic Deserialization:
JsonDeserializerব্যবহার করে JSON থেকেsuperclassএবংsubclassঅবজেক্ট ডেসিরিয়ালাইজ করা হয়, এবং JSON-এ থাকা টাইপ অনুযায়ী সঠিক অবজেক্টে রূপান্তর করা হয়। - এই কৌশলটি সাধারণত ইনহেরিটেন্স সম্পর্কিত অবজেক্টগুলির জন্য ব্যবহৃত হয় যেখানে আপনি একটি ক্লাস হায়ারার্কি থেকে ডেটা প্রক্রিয়া করতে চান।
Gson এ Interface এবং Abstract Class এর জন্য সেরিয়ালাইজেশন (JSON-এ রূপান্তর) এবং ডেসিরিয়ালাইজেশন (JSON থেকে Java অবজেক্টে রূপান্তর) করতে কিছু বিশেষ কৌশল ব্যবহার করতে হয়, কারণ Gson ডিফল্টভাবে Interface বা Abstract Class কে সঠিকভাবে সেরিয়ালাইজ বা ডেসিরিয়ালাইজ করতে পারে না। আপনি TypeAdapter অথবা JsonAdapter ব্যবহার করে কাস্টম লজিক বাস্তবায়ন করতে পারেন।
উদাহরণ: Interface এবং Abstract Class এর জন্য Gson ব্যবহার
1. Abstract Class এবং Interface এর সেরিয়ালাইজেশন এবং ডেসিরিয়ালাইজেশন
ধরা যাক, আমাদের একটি Shape নামক abstract class রয়েছে এবং এটি দুইটি subclass: Circle এবং Rectangle দ্বারা এক্সটেন্ড করা হয়েছে। Shape ক্লাসটি একটি interface যা বিভিন্ন ধরনের শেপের জন্য ব্যবহৃত হবে।
এখন, আমাদের এই Shape ক্লাসের অবজেক্টকে JSON-এ রূপান্তর করতে এবং JSON থেকে Java অবজেক্টে রূপান্তর করতে হবে।
Solution 1: TypeAdapter ব্যবহার করে
এখানে Shape ইন্টারফেস বা অ্যাবস্ট্র্যাক্ট ক্লাসকে JSON-এ কনভার্ট করার জন্য কাস্টম TypeAdapter ব্যবহার করতে হবে, যাতে আমরা JSON-এ type ফিল্ড যোগ করতে পারি যা নির্দেশ করবে যে অবজেক্টটি কোন সাবক্লাসের।
উদাহরণ কোড:
import com.google.gson.*;
import java.lang.reflect.Type;
// Abstract Class
abstract class Shape {
int x, y;
abstract void draw();
}
// Subclass 1: Circle
class Circle extends Shape {
int radius;
public Circle(int x, int y, int radius) {
this.x = x;
this.y = y;
this.radius = radius;
}
@Override
void draw() {
System.out.println("Drawing Circle");
}
}
// Subclass 2: Rectangle
class Rectangle extends Shape {
int width, height;
public Rectangle(int x, int y, int width, int height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
@Override
void draw() {
System.out.println("Drawing Rectangle");
}
}
// TypeAdapter for Shape
class ShapeAdapter implements JsonSerializer<Shape>, JsonDeserializer<Shape> {
@Override
public JsonElement serialize(Shape src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject jsonObject = new JsonObject();
// Adding type to identify subclass type
if (src instanceof Circle) {
jsonObject.addProperty("type", "Circle");
jsonObject.add("data", context.serialize(src));
} else if (src instanceof Rectangle) {
jsonObject.addProperty("type", "Rectangle");
jsonObject.add("data", context.serialize(src));
}
return jsonObject;
}
@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 ("Circle".equals(type)) {
shape = context.deserialize(jsonObject.get("data"), Circle.class);
} else if ("Rectangle".equals(type)) {
shape = context.deserialize(jsonObject.get("data"), Rectangle.class);
}
return shape;
}
}
public class Main {
public static void main(String[] args) {
// Create a Circle object
Shape circle = new Circle(10, 20, 15);
Shape rectangle = new Rectangle(5, 5, 30, 40);
// Create Gson with TypeAdapter
Gson gson = new GsonBuilder()
.registerTypeAdapter(Shape.class, new ShapeAdapter())
.create();
// Serialize Circle object to JSON
String jsonCircle = gson.toJson(circle);
System.out.println("Serialized Circle: " + jsonCircle);
// Deserialize Circle JSON back to Java object
Shape deserializedCircle = gson.fromJson(jsonCircle, Shape.class);
System.out.println("Deserialized Circle: ");
deserializedCircle.draw();
// Serialize Rectangle object to JSON
String jsonRectangle = gson.toJson(rectangle);
System.out.println("Serialized Rectangle: " + jsonRectangle);
// Deserialize Rectangle JSON back to Java object
Shape deserializedRectangle = gson.fromJson(jsonRectangle, Shape.class);
System.out.println("Deserialized Rectangle: ");
deserializedRectangle.draw();
}
}
আউটপুট:
Serialized Circle: {"type":"Circle","data":{"x":10,"y":20,"radius":15}}
Deserialized Circle:
Drawing Circle
Serialized Rectangle: {"type":"Rectangle","data":{"x":5,"y":5,"width":30,"height":40}}
Deserialized Rectangle:
Drawing Rectangle
ব্যাখ্যা:
Shapeএকটি অ্যাবস্ট্র্যাক্ট ক্লাস যাCircleএবংRectangleএর মতো subclass গুলোকে প্রতিনিধিত্ব করে।- ShapeAdapter ক্লাসটি
Shapeঅবজেক্টের জন্য কাস্টম সেরিয়ালাইজেশন এবং ডেসিরিয়ালাইজেশন লজিক প্রযোগ করে। এখানে আমরাtypeফিল্ড যোগ করেছি যাতেCircleএবংRectangleএর পার্থক্য করা যায়। - Serialization:
ShapeAdapterব্যবহার করেCircleএবংRectangleকে JSON এ রূপান্তর করা হয়েছে। - Deserialization: JSON থেকে
Shapeঅবজেক্টে রূপান্তর করা হয়েছে এবং JSON এরtypeফিল্ড ব্যবহার করে সঠিক সাবক্লাসে রূপান্তর করা হয়েছে।
Solution 2: @JsonAdapter অ্যানোটেশন ব্যবহার করা
@JsonAdapter অ্যানোটেশনটি ক্লাস অথবা ফিল্ডের জন্য কাস্টম TypeAdapter যুক্ত করার জন্য ব্যবহৃত হয়। এটি উপরের কোডের মতো কাস্টম অ্যাডাপ্টার ব্যবহার করার জন্য সুবিধাজনক হতে পারে।
উদাহরণ:
import com.google.gson.annotations.JsonAdapter;
@JsonAdapter(ShapeAdapter.class)
abstract class Shape {
int x, y;
abstract void draw();
}
এখানে Shape ক্লাসের উপরে @JsonAdapter(ShapeAdapter.class) অ্যানোটেশন ব্যবহার করা হয়েছে, যা ShapeAdapter কে সেরিয়ালাইজেশন এবং ডেসিরিয়ালাইজেশন কাস্টম লজিক হিসেবে অ্যাসাইন করে।
- Gson দিয়ে Interface এবং Abstract Class এর জন্য সেরিয়ালাইজেশন এবং ডেসিরিয়ালাইজেশন করতে হলে আপনাকে
TypeAdapterঅথবাJsonAdapterব্যবহার করতে হবে। - আপনি কাস্টম সেরিয়ালাইজেশন এবং ডেসিরিয়ালাইজেশন লজিক তৈরি করে, সাবক্লাসের পার্থক্য নির্ধারণ এবং JSON ফিল্ডকে কাস্টমাইজ করতে পারেন।
- TypeAdapter অথবা
@JsonAdapterঅ্যানোটেশন ব্যবহারের মাধ্যমে Interface এবং Abstract Class এর জন্য কাস্টম লজিক সহজেই বাস্তবায়ন করা সম্ভব।
Gson এর Custom Type Adapter ব্যবহার করে আপনি polymorphism (অথবা বিভিন্ন ধরনের অবজেক্টের জন্য একই ধরনের ইন্টারফেস বা শ্রেণী) হ্যান্ডল করতে পারেন। polymorphism হ্যান্ডলিং তখন প্রয়োজন হয় যখন আপনার JSON ডাটা বিভিন্ন ধরনের অবজেক্ট ধারণ করে এবং আপনি চাইছেন যে Gson সেগুলিকে সঠিকভাবে ডেসিরিয়ালাইজ (পড়তে) ও সিরিয়ালাইজ (লিখতে) করতে পারে।
এটি সাধারনত বিভিন্ন ধরনের অবজেক্টের জন্য একই বেস ক্লাস বা ইন্টারফেস ব্যবহার করে JSON ডাটা তৈরি ও পড়ার সময় দরকার হয়। Gson এর ডিফল্ট ডেসিরিয়ালাইজেশন এবং সিরিয়ালাইজেশন পদ্ধতি polymorphic অবজেক্ট হ্যান্ডলিংয়ের জন্য প্রস্তুত নয়, তবে আপনি Custom Type Adapter তৈরি করে এটি হ্যান্ডল করতে পারেন।
উদাহরণ:
ধরা যাক, আপনার একটি বেস ক্লাস Animal আছে এবং তার দুটি সিড (derived) ক্লাস Dog এবং Cat রয়েছে। এইসব অবজেক্টের জন্য আপনাকে JSON স্ট্রাকচার হ্যান্ডল করতে হবে।
Step 1: বেস ক্লাস এবং derived ক্লাস তৈরি করা
class Animal {
String name;
public Animal(String name) {
this.name = name;
}
public String makeSound() {
return "Some sound";
}
}
class Dog extends Animal {
public Dog(String name) {
super(name);
}
@Override
public String makeSound() {
return "Bark";
}
}
class Cat extends Animal {
public Cat(String name) {
super(name);
}
@Override
public String makeSound() {
return "Meow";
}
}
Step 2: Custom Type Adapter তৈরি করা
এখন, আপনাকে TypeAdapter তৈরি করতে হবে যাতে Dog এবং Cat অবজেক্টগুলো সঠিকভাবে ডেসিরিয়ালাইজ এবং সিরিয়ালাইজ হতে পারে।
import com.google.gson.*;
import java.lang.reflect.Type;
class AnimalAdapter implements JsonSerializer<Animal>, JsonDeserializer<Animal> {
@Override
public JsonElement serialize(Animal src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject jsonObject = new JsonObject();
// Serialize the common field (name)
jsonObject.addProperty("name", src.name);
// Serialize the specific fields depending on the subclass type
if (src instanceof Dog) {
jsonObject.addProperty("type", "dog");
jsonObject.addProperty("sound", src.makeSound());
} else if (src instanceof Cat) {
jsonObject.addProperty("type", "cat");
jsonObject.addProperty("sound", src.makeSound());
}
return jsonObject;
}
@Override
public Animal deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonObject jsonObject = json.getAsJsonObject();
String name = jsonObject.get("name").getAsString();
String type = jsonObject.get("type").getAsString();
// Create the correct subclass instance based on the 'type' field in the JSON
if ("dog".equals(type)) {
return new Dog(name);
} else if ("cat".equals(type)) {
return new Cat(name);
} else {
throw new JsonParseException("Unknown type: " + type);
}
}
}
Step 3: GsonBuilder দিয়ে Custom TypeAdapter রেজিস্টার করা
এখন, GsonBuilder ব্যবহার করে কাস্টম TypeAdapter রেজিস্টার করতে হবে:
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public class PolymorphismWithGson {
public static void main(String[] args) {
// Create a Dog and a Cat instance
Animal dog = new Dog("Buddy");
Animal cat = new Cat("Whiskers");
// Create a Gson object with the custom TypeAdapter
Gson gson = new GsonBuilder()
.registerTypeAdapter(Animal.class, new AnimalAdapter())
.create();
// Serialize the Animal objects
String dogJson = gson.toJson(dog);
String catJson = gson.toJson(cat);
System.out.println("Serialized Dog: " + dogJson);
System.out.println("Serialized Cat: " + catJson);
// Deserialize the JSON back into Animal objects
Animal deserializedDog = gson.fromJson(dogJson, Animal.class);
Animal deserializedCat = gson.fromJson(catJson, Animal.class);
System.out.println("Deserialized Dog: " + deserializedDog.makeSound());
System.out.println("Deserialized Cat: " + deserializedCat.makeSound());
}
}
আউটপুট:
Serialized Dog: {"name":"Buddy","type":"dog","sound":"Bark"}
Serialized Cat: {"name":"Whiskers","type":"cat","sound":"Meow"}
Deserialized Dog: Bark
Deserialized Cat: Meow
ব্যাখ্যা:
- Custom TypeAdapter:
AnimalAdapterক্লাসটিJsonSerializerএবংJsonDeserializerইন্টারফেস ইমপ্লিমেন্ট করেছে।serializeমেথড: এখানেAnimalঅবজেক্টের ধরন (subclass) অনুযায়ী JSON স্ট্রাকচার তৈরি করা হচ্ছে।DogএবংCatএর জন্য আলাদা"type"ফিল্ড দেওয়া হচ্ছে।deserializeমেথড: এখানে JSON থেকে অবজেক্ট তৈরি করার সময়typeফিল্ডের মান দেখে সঠিক subclass (যেমনDogবাCat) নির্ধারণ করা হচ্ছে।
- GsonBuilder:
registerTypeAdapter(Animal.class, new AnimalAdapter())ব্যবহার করে আমরাAnimalক্লাসের জন্য কাস্টমTypeAdapterরেজিস্টার করেছি, যাতে Gson এর সিরিয়ালাইজেশন এবং ডেসিরিয়ালাইজেশন কাস্টম লজিক অনুসারে চলে। - Polymorphic Serialization & Deserialization:
- সিরিয়ালাইজেশনে,
DogএবংCatএর মধ্যে পার্থক্য করতে"type"ফিল্ড ব্যবহার করা হয়েছে। - ডেসিরিয়ালাইজেশনে,
"type"ফিল্ড দেখে সঠিক subclass নির্বাচন করা হয়েছে।
- সিরিয়ালাইজেশনে,
- Polymorphism হ্যান্ডল করতে Gson এর Custom Type Adapter খুবই শক্তিশালী একটি পদ্ধতি।
- আপনি যখন polymorphic অবজেক্টের জন্য JSON তৈরি বা JSON থেকে অবজেক্ট তৈরি করতে চান, তখন Custom TypeAdapter আপনাকে কাস্টম সিরিয়ালাইজেশন ও ডেসিরিয়ালাইজেশন লজিক প্রয়োগ করার সুযোগ দেয়।
- এটি বিশেষভাবে উপকারী যখন আপনার অবজেক্টের ধরন ডায়নামিকভাবে পরিবর্তিত হয় এবং Gson ডিফল্টভাবে এটি হ্যান্ডল করতে পারে না।
Read more