গসন সহ বহুবর্ষ


103

জিসনের সাথে জেসন স্ট্রিংটি ডিসরিয়ালাইজ করতে আমার একটি সমস্যা আছে। আমি কমান্ডগুলির একটি অ্যারে পাই। কমান্ডটি শুরু হতে পারে, থামাতে পারে, অন্য কোনও ধরনের কমান্ড। স্বাভাবিকভাবেই আমার পলিমারফিজম রয়েছে এবং কমান্ড থেকে উত্তরাধিকার সূচনা / বন্ধ করুন।

আমি কীভাবে এটি জিএসএন ব্যবহার করে সঠিক কমান্ড অবজেক্টে সিরিয়ালাইজ করতে পারি?

দেখে মনে হচ্ছে যে আমি কেবল বেস টাইপটি পাই, এটি ঘোষিত টাইপ এবং কখনই রানটাইম টাইপ নয়।


উত্তর:


120

এটি কিছুটা দেরীতে হলেও আজ আমাকে ঠিক একই জিনিসটি করতে হয়েছিল। সুতরাং, আমার গবেষণা উপর ভিত্তি করে এবং যখন gson-2.0 ব্যবহার করে আপনি সত্যিই ব্যবহার করতে না চান registerTypeHierarchyAdapter পদ্ধতি, বরং আরো জাগতিক registerTypeAdapter । এবং আপনার অবশ্যই উত্পন্ন শ্রেণীর জন্য উদাহরণস্বরূপ বা অ্যাডাপ্টার লেখার দরকার নেই : বেস ক্লাস বা ইন্টারফেসের জন্য কেবল একটি অ্যাডাপ্টারের অবশ্যই সরবরাহ করা হয়েছে যে আপনি উত্পন্ন ক্লাসগুলির ডিফল্ট ক্রমিকায় সন্তুষ্ট। যাইহোক, এখানে কোড (প্যাকেজ এবং আমদানি সরানো হয়েছে) ( গিথুবেও উপলভ্য ):

বেস ক্লাস (আমার ক্ষেত্রে ইন্টারফেস):

public interface IAnimal { public String sound(); }

দুটি উত্পন্ন ক্লাস, বিড়াল:

public class Cat implements IAnimal {

    public String name;

    public Cat(String name) {
        super();
        this.name = name;
    }

    @Override
    public String sound() {
        return name + " : \"meaow\"";
    };
}

এবং কুকুর:

public class Dog implements IAnimal {

    public String name;
    public int ferocity;

    public Dog(String name, int ferocity) {
        super();
        this.name = name;
        this.ferocity = ferocity;
    }

    @Override
    public String sound() {
        return name + " : \"bark\" (ferocity level:" + ferocity + ")";
    }
}

আইআনিমাল অ্যাডাপ্টার:

public class IAnimalAdapter implements JsonSerializer<IAnimal>, JsonDeserializer<IAnimal>{

    private static final String CLASSNAME = "CLASSNAME";
    private static final String INSTANCE  = "INSTANCE";

    @Override
    public JsonElement serialize(IAnimal src, Type typeOfSrc,
            JsonSerializationContext context) {

        JsonObject retValue = new JsonObject();
        String className = src.getClass().getName();
        retValue.addProperty(CLASSNAME, className);
        JsonElement elem = context.serialize(src); 
        retValue.add(INSTANCE, elem);
        return retValue;
    }

    @Override
    public IAnimal deserialize(JsonElement json, Type typeOfT,
            JsonDeserializationContext context) throws JsonParseException  {
        JsonObject jsonObject = json.getAsJsonObject();
        JsonPrimitive prim = (JsonPrimitive) jsonObject.get(CLASSNAME);
        String className = prim.getAsString();

        Class<?> klass = null;
        try {
            klass = Class.forName(className);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            throw new JsonParseException(e.getMessage());
        }
        return context.deserialize(jsonObject.get(INSTANCE), klass);
    }
}

এবং পরীক্ষা ক্লাস:

public class Test {

    public static void main(String[] args) {
        IAnimal animals[] = new IAnimal[]{new Cat("Kitty"), new Dog("Brutus", 5)};
        Gson gsonExt = null;
        {
            GsonBuilder builder = new GsonBuilder();
            builder.registerTypeAdapter(IAnimal.class, new IAnimalAdapter());
            gsonExt = builder.create();
        }
        for (IAnimal animal : animals) {
            String animalJson = gsonExt.toJson(animal, IAnimal.class);
            System.out.println("serialized with the custom serializer:" + animalJson);
            IAnimal animal2 = gsonExt.fromJson(animalJson, IAnimal.class);
            System.out.println(animal2.sound());
        }
    }
}

আপনি যখন পরীক্ষা চালাবেন :: মূল আপনি নিম্নলিখিত আউটপুটটি পান:

serialized with the custom serializer:
{"CLASSNAME":"com.synelixis.caches.viz.json.playground.plainAdapter.Cat","INSTANCE":{"name":"Kitty"}}
Kitty : "meaow"
serialized with the custom serializer:
{"CLASSNAME":"com.synelixis.caches.viz.json.playground.plainAdapter.Dog","INSTANCE":{"name":"Brutus","ferocity":5}}
Brutus : "bark" (ferocity level:5)

আমি প্রকৃতপক্ষে রেজিস্ট্রার টাইপ হাইয়ারকি অ্যাডাপ্টার পদ্ধতিটি ব্যবহার করেও উপরের কাজটি করেছি , তবে কাস্টম ডগএডাপ্টার এবং ক্যাটএডাপ্টার সিরিয়ালাইজার / ডিসরিযায়ার ক্লাসগুলি প্রয়োগ করা দরকার যা আপনি কুকুর বা বিড়ালের সাথে অন্য কোনও ক্ষেত্র যুক্ত করতে চান এমন সময় বজায় রাখতে ব্যথা হয়।


5
নোট করুন যে Class.forName ব্যবহার করে শ্রেণীর নামগুলির সিরিয়ালাইজেশন এবং deserialization (ব্যবহারকারী ইনপুট থেকে) কিছু পরিস্থিতিতে সুরক্ষা জড়িত উপস্থিত করতে পারে, এবং এইভাবে Gson দেব টিম দ্বারা নিরুৎসাহিত করা হয়। কোড.google.com/p/google-gson/issues/detail?id=340#c2
প্রোগ্রামার ব্রুস

4
সিরিয়ালাইজেশনে অসীম লুপ না পাওয়ার জন্য আপনি কীভাবে পরিচালনা করেছিলেন, আপনি প্রসঙ্গটি কল করছেন ;সিরিয়ালাইজ (এসসিআর); যা আপনার অ্যাডাপ্টারটি আবার চাওয়া হবে। আমার অনুরূপ কোডে এটি ঘটেছিল।
চে জাভারা

6
ভুল। এই সমাধান কাজ করে না। যদি আপনি প্রসঙ্গকে কল করেন any কোনওভাবেই ট্রায়াল করুন আপনি অসীম পুনরাবৃত্তি দিয়ে শেষ হবেন। আমি অবাক হয়েছি কেন লোকেরা আসলে কোড টেস্টিং ছাড়াই পোস্ট করে। আমি ২.২.১ দিয়ে চেষ্টা করেছি। বাগ বর্ণিত দেখুন stackoverflow.com/questions/13244769/...
চে javara

4
@ মার্কাসজুনিয়াস ব্রুটাস আমি আপনার কোডটি চালিয়েছি এবং মনে হচ্ছে এটি কেবল এই বিশেষ ক্ষেত্রে কাজ করে - কারণ আপনি একটি সুপারইন্টারফেস আইআইনিমাল সংজ্ঞায়িত করেছেন এবং আইআনিমাল অ্যাডাপ্টার এটি ব্যবহার করে। পরিবর্তে যদি আপনার কেবল 'বিড়াল' থাকে তবে আপনি অসীম পুনরাবৃত্তি সমস্যাটি পাবেন। সুতরাং এই সমাধানটি এখনও সাধারণ ক্ষেত্রে কাজ করে না - কেবলমাত্র যখন আপনি একটি সাধারণ ইন্টারফেস সংজ্ঞায়িত করতে সক্ষম হন। আমার ক্ষেত্রে কোনও ইন্টারফেস ছিল না তাই আমাকে টাইপএডাপ্টারফ্যাক্টরির সাথে আলাদা পদ্ধতির ব্যবহার করতে হয়েছিল।
চে জাভারা

2
ব্যবহারকারীর src.getClass ()। Src.getClass () এর পরিবর্তে getName ()। GetCanonicalName ()। এই কোডগুলি অভ্যন্তরীণ / নেস্টেড ক্লাসগুলির জন্যও কাজ করবে ads
mR_fr0g

13

গসনের কাছে বর্তমানে টাইপ হায়ারার্কি অ্যাডাপ্টারের নিবন্ধকরণের একটি ব্যবস্থা রয়েছে যা সাধারণ পলিমারফিক ডিসরিয়ালাইজেশনের জন্য কনফিগার করা যেতে পারে তবে আমি কীভাবে তা দেখতে পাচ্ছি না, যেমন টাইপ হায়ারার্কি অ্যাডাপ্টারটি কেবল একটি সংযুক্ত সিরিয়ালাইজার / ডিসারিয়ালাইজার / উদাহরণ স্রষ্টা হিসাবে উপস্থিত হয়, কোনও প্রকৃত পলিমারফিক ধরণের নিবন্ধীকরণ না দিয়ে কোডার পর্যন্ত উদাহরণস্বরূপ সৃষ্টির বিবরণ রেখে leaving

দেখে মনে হচ্ছে গসন শীঘ্রই RuntimeTypeAdapterসরল পলিমারফিকিক ডিসরিয়ালাইজেশনের ব্যবস্থা গ্রহণ করবে । আরও তথ্যের জন্য http://code.google.com/p/google-gson/issues/detail?id=231 দেখুন ।

যদি RuntimeTypeAdapterনতুনটির ব্যবহার সম্ভব না হয় এবং আপনি জিএসন ব্যবহার করতে চান তবে আমি মনে করি আপনাকে নিজের সমাধান সমাধান করতে হবে, একটি কাস্টম ডিসারিয়ালাইজারকে টাইপ হায়ারার্কি অ্যাডাপ্টার হিসাবে বা টাইপ অ্যাডাপ্টার হিসাবে নিবন্ধন করতে হবে। নিম্নলিখিত যেমন একটি উদাহরণ।

// output:
//     Starting machine1
//     Stopping machine2

import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;

import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;

public class Foo
{
  // [{"machine_name":"machine1","command":"start"},{"machine_name":"machine2","command":"stop"}]
  static String jsonInput = "[{\"machine_name\":\"machine1\",\"command\":\"start\"},{\"machine_name\":\"machine2\",\"command\":\"stop\"}]";

  public static void main(String[] args)
  {
    GsonBuilder gsonBuilder = new GsonBuilder();
    gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES);
    CommandDeserializer deserializer = new CommandDeserializer("command");
    deserializer.registerCommand("start", Start.class);
    deserializer.registerCommand("stop", Stop.class);
    gsonBuilder.registerTypeAdapter(Command.class, deserializer);
    Gson gson = gsonBuilder.create();
    Command[] commands = gson.fromJson(jsonInput, Command[].class);
    for (Command command : commands)
    {
      command.execute();
    }
  }
}

class CommandDeserializer implements JsonDeserializer<Command>
{
  String commandElementName;
  Gson gson;
  Map<String, Class<? extends Command>> commandRegistry;

  CommandDeserializer(String commandElementName)
  {
    this.commandElementName = commandElementName;
    GsonBuilder gsonBuilder = new GsonBuilder();
    gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES);
    gson = gsonBuilder.create();
    commandRegistry = new HashMap<String, Class<? extends Command>>();
  }

  void registerCommand(String command, Class<? extends Command> commandInstanceClass)
  {
    commandRegistry.put(command, commandInstanceClass);
  }

  @Override
  public Command deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
      throws JsonParseException
  {
    try
    {
      JsonObject commandObject = json.getAsJsonObject();
      JsonElement commandTypeElement = commandObject.get(commandElementName);
      Class<? extends Command> commandInstanceClass = commandRegistry.get(commandTypeElement.getAsString());
      Command command = gson.fromJson(json, commandInstanceClass);
      return command;
    }
    catch (Exception e)
    {
      throw new RuntimeException(e);
    }
  }
}

abstract class Command
{
  String machineName;

  Command(String machineName)
  {
    this.machineName = machineName;
  }

  abstract void execute();
}

class Stop extends Command
{
  Stop(String machineName)
  {
    super(machineName);
  }

  void execute()
  {
    System.out.println("Stopping " + machineName);
  }
}

class Start extends Command
{
  Start(String machineName)
  {
    super(machineName);
  }

  void execute()
  {
    System.out.println("Starting " + machineName);
  }
}

আপনি যদি এপিআইগুলি পরিবর্তন করতে পারেন, তবে নোট করুন যে জ্যাকসনের কাছে বর্তমানে তুলনামূলকভাবে সহজ পলিমারফিকিক ডিসরিয়ালাইজেশনের একটি ব্যবস্থা রয়েছে। আমি প্রোগ্রামারব্রুস.ব্লগস্পট.কম
প্রোগ্রামার ব্রুস

RuntimeTypeAdapterএখন সম্পূর্ণ, দুর্ভাগ্যক্রমে এটি জসন কোর এ এখনও মনে হচ্ছে না। :-(
জোনাথন

8

মার্কাস জুনিয়াস ব্রুটাসের দুর্দান্ত উত্তর ছিল (ধন্যবাদ!) তার উদাহরণটি প্রসারিত করতে, আপনি নিম্নলিখিত পরিবর্তনগুলি সহ সমস্ত ধরণের অবজেক্টের জন্য (কেবল আইআনিমাল নয়) কাজ করার জন্য তার অ্যাডাপ্টার শ্রেণিকে জেনেরিক তৈরি করতে পারেন:

class InheritanceAdapter<T> implements JsonSerializer<T>, JsonDeserializer<T>
{
....
    public JsonElement serialize(T src, Type typeOfSrc, JsonSerializationContext context)
....
    public T deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
....
}

এবং টেস্ট ক্লাসে:

public class Test {
    public static void main(String[] args) {
        ....
            builder.registerTypeAdapter(IAnimal.class, new InheritanceAdapter<IAnimal>());
        ....
}

1
তার সমাধানটি বাস্তবায়নের পরে আমার পরবর্তী চিন্তাটি হ'ল :-)
ডেভিড লেভি

7

জিএসএন-এর একটি দুর্দান্ত পরীক্ষার কেস রয়েছে যা এখানে টাইপ হায়ারার্কি অ্যাডাপ্টারকে সংজ্ঞায়িত ও নিবন্ধভুক্ত করার পদ্ধতি দেখায়।

http://code.google.com/p/google-gson/source/browse/trunk/gson/src/test/java/com/google/gson/functional/TypeHierarchyAdapterTest.java?r=739

এটি করার জন্য এটি করুন:

    gson = new GsonBuilder()
          .registerTypeAdapter(BaseQuestion.class, new BaseQuestionAdaptor())
          .create();

অ্যাডাপ্টারের সিরিয়ালাইজ পদ্ধতিটি ক্যাসকেডিং হতে পারে যদি তা হয় না তবে এটি কী ধরণের সিরিয়ালাইজ করছে তা পরীক্ষা করে দেখুন।

    JsonElement result = new JsonObject();

    if (src instanceof SliderQuestion) {
        result = context.serialize(src, SliderQuestion.class);
    }
    else if (src instanceof TextQuestion) {
        result = context.serialize(src, TextQuestion.class);
    }
    else if (src instanceof ChoiceQuestion) {
        result = context.serialize(src, ChoiceQuestion.class);
    }

    return result;

ডিসরিয়ালাইজিং কিছুটা হ্যাকি। ইউনিট পরীক্ষার উদাহরণে, কোন শ্রেণীর deserialized করা হবে তা নির্ধারণ করার জন্য এটি টেল-ট্যল বৈশিষ্ট্যগুলির অস্তিত্বের জন্য পরীক্ষা করে। আপনি যদি সিরিয়াল করছেন এমন অবজেক্টের উত্সটি পরিবর্তন করতে পারেন তবে আপনি প্রতিটি উদাহরণে একটি 'ক্লাসটাইপ' বৈশিষ্ট্য যুক্ত করতে পারেন যা উদাহরণ শ্রেণীর নামের FQN ধারণ করে। এটি যদিও খুব আন-অবজেক্ট-ভিত্তিক।


4

গুগল নিজস্ব রানটাইমটাইপএডাপ্টারফ্যাক্টরি প্রকাশ করেছে পরিচালনা করতে তবে দুর্ভাগ্যক্রমে এটি জিএসন কোরের অংশ নয় (আপনার প্রকল্পটি অবশ্যই ক্লাসটি অনুলিপি করে আটকান)।

উদাহরণ:

RuntimeTypeAdapterFactory<Animal> runtimeTypeAdapterFactory = RuntimeTypeAdapterFactory
.of(Animal.class, "type")
.registerSubtype(Dog.class, "dog")
.registerSubtype(Cat.class, "cat");

Gson gson = new GsonBuilder()
    .registerTypeAdapterFactory(runtimeTypeAdapterFactory)
    .create();

এখানে আমি প্রাণী, কুকুর এবং বিড়াল মডেলগুলি ব্যবহার করে এর সম্পূর্ণ কার্যকারী উদাহরণ পোস্ট করেছি।

আমি মনে করি এটি স্ক্র্যাচ থেকে রিম্প্লেমেন্ট না করে এই অ্যাডাপ্টারের উপর নির্ভর করা ভাল।


2

দীর্ঘ সময় অতিবাহিত হয়েছে, তবে আমি অনলাইনে সত্যিই খুব ভাল সমাধানটি খুঁজে পেলাম না @ এখানে @ মার্কাসজুনিয়াস ব্রুটাসের সমাধানের উপর একটি ছোট টুইস্ট রয়েছে, যা অসীম পুনরাবৃত্তি এড়িয়ে চলে।

একই ডিসরিয়ালাইজার রাখুন, তবে সিরিয়ালাইজারটি সরান -

public class IAnimalAdapter implements JsonDeSerializer<IAnimal> {
  private static final String CLASSNAME = "CLASSNAME";
  private static final String INSTANCE  = "INSTANCE";

  @Override
  public IAnimal deserialize(JsonElement json, Type typeOfT,
        JsonDeserializationContext context) throws JsonParseException  {
    JsonObject jsonObject =  json.getAsJsonObject();
    JsonPrimitive prim = (JsonPrimitive) jsonObject.get(CLASSNAME);
    String className = prim.getAsString();

    Class<?> klass = null;
    try {
        klass = Class.forName(className);
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
        throw new JsonParseException(e.getMessage());
    }
    return context.deserialize(jsonObject.get(INSTANCE), klass);
  }
}

তারপরে আপনার মূল ক্লাসে একটি ক্ষেত্র যুক্ত করুন @SerializedName("CLASSNAME")। কৌতুকটি এখন বেস ক্লাসের কনস্ট্রাক্টরে এটি সূচনা করার জন্য, তাই আপনার ইন্টারফেসটিকে একটি বিমূর্ত শ্রেণিতে পরিণত করুন।

public abstract class IAnimal {
  @SerializedName("CLASSNAME")
  public String className;

  public IAnimal(...) {
    ...
    className = this.getClass().getName();
  }
}

এখানে অসীম পুনরাবৃত্তি না হওয়ার কারণটি হ'ল আমরা আসল রানটাইম ক্লাসটি (অর্থাৎ কুকুরটি আইএনিমাল নয়) পাস করি context.deserialize। এটি আমাদের টাইপ অ্যাডাপ্টারকে কল করবে না, যতক্ষণ আমরা ব্যবহার করি registerTypeAdapterএবং না করিregisterTypeHierarchyAdapter


2

আপডেট করা উত্তর - অন্যান্য সমস্ত উত্তরের সেরা অংশ

আমি বিভিন্ন ব্যবহারের ক্ষেত্রে সমাধানগুলির বর্ণনা দিচ্ছি এবং পাশাপাশি অসীম পুনরাবৃত্তি সমস্যার সমাধান করব

  • কেস 1: আপনি ক্লাসগুলির নিয়ন্ত্রণে রয়েছেন , অর্থাত্ আপনার নিজের লেখার জন্য Cat, Dogক্লাসগুলির পাশাপাশিIAnimal ইন্টারফেসটিও । আপনি কেবলমাত্র @ মার্কাস-জুনিয়াস-ব্রুফাস (শীর্ষের উত্তর) দ্বারা সরবরাহিত সমাধানটি অনুসরণ করতে পারেন

    কোনও সাধারণ বেস ইন্টারফেস থাকলে কোনও অসীম পুনরাবৃত্তি হবে না IAnimal

    তবে, যদি আমি IAnimalবা এই জাতীয় কোনও ইন্টারফেস বাস্তবায়ন করতে না চাই ?

    তারপরে, @ মারকাস-জুনিয়াস-ব্রুরাস (শীর্ষ রেট করা উত্তর) অসীম পুনরাবৃত্তি ত্রুটি তৈরি করবে। এই ক্ষেত্রে, আমরা নীচের মতো কিছু করতে পারি।

    নীচে বেস ক্লাসের ভিতরে একটি কপি কনস্ট্রাক্টর এবং একটি র‌্যাপার সাবক্লাস তৈরি করতে হবে :

// Base class(modified)
public class Cat implements IAnimal {

    public String name;

    public Cat(String name) {
        super();
        this.name = name;
    }
    // COPY CONSTRUCTOR
    public Cat(Cat cat) {
        this.name = cat.name;
    }

    @Override
    public String sound() {
        return name + " : \"meaow\"";
    };
}



    // The wrapper subclass for serialization
public class CatWrapper extends Cat{


    public CatWrapper(String name) {
        super(name);
    }

    public CatWrapper(Cat cat) {
        super(cat);
    }
}

এবং ধরণের সিরিয়ালাইজার Cat:

public class CatSerializer implements JsonSerializer<Cat> {

    @Override
    public JsonElement serialize(Cat src, Type typeOfSrc, JsonSerializationContext context) {

        // Essentially the same as the type Cat
        JsonElement catWrapped = context.serialize(new CatWrapper(src));

        // Here, we can customize the generated JSON from the wrapper as we want.
        // We can add a field, remove a field, etc.


        return modifyJSON(catWrapped);
    }

    private JsonElement modifyJSON(JsonElement base){
        // TODO: Modify something
        return base;
    }
}

সুতরাং, কেন একটি অনুলিপি নির্মাণকারী?

ভাল, একবার আপনি অনুলিপি নির্ধারককে সংজ্ঞায়িত করুন, বেস ক্লাসটি যতই বদলে যায় না কেন, আপনার র‍্যাপার একই ভূমিকা নিয়ে চালিয়ে যাবে। দ্বিতীয়ত, আমরা যদি কোনও অনুলিপি নির্মাণকারীকে সংজ্ঞায়িত না করি এবং কেবল বেস ক্লাসটি সাবক্লাস করি তবে আমাদের বর্ধিত শ্রেণীর শর্তে "কথা বলতে" হবে, অর্থাৎ,CatWrapper । এটি সম্পূর্ণ সম্ভব যে আপনার উপাদানগুলি বেস ক্লাসের সাথে কথা বলে এবং মোড়ক প্রকারের সাথে নয়।

একটি সহজ বিকল্প আছে?

অবশ্যই, এটি এখন গুগল দ্বারা চালু করা হয়েছিল - এটি RuntimeTypeAdapterFactoryবাস্তবায়ন:

RuntimeTypeAdapterFactory<Animal> runtimeTypeAdapterFactory = RuntimeTypeAdapterFactory
.of(Animal.class, "type")
.registerSubtype(Dog.class, "dog")
.registerSubtype(Cat.class, "cat");

Gson gson = new GsonBuilder()
    .registerTypeAdapterFactory(runtimeTypeAdapterFactory)
    .create();

এখানে, আপনাকে "বিড়াল" হওয়ার জন্য "টাইপ" নামক একটি ক্ষেত্র Animalএবং একই অভ্যন্তরের মান Dog"কুকুর" Catহতে হবে

সম্পূর্ণ উদাহরণ: https://static.javadoc.io/org.danilopianini/gson-extras/0.2.1/com/google/gson/typeadapters/ রুনটাইম টাইপএডাপ্টারফ্যাক্টরি html

  • কেস ২: আপনি ক্লাসগুলির নিয়ন্ত্রণে নন । আপনি কোনও সংস্থায় যোগদান করেন বা একটি লাইব্রেরি ব্যবহার করুন যেখানে ক্লাসগুলি ইতিমধ্যে সংজ্ঞায়িত হয়েছে এবং আপনার ম্যানেজার চান না যে আপনি সেগুলি কোনওভাবেই বদলাতে পারেন - আপনি আপনার ক্লাসগুলি সাবক্লাস করতে পারেন এবং একটি সাধারণ চিহ্নিতকারী ইন্টারফেস প্রয়োগ করতে পারেন (যার কোনও পদ্ধতি নেই) ) যেমন AnimalInterface

    উদা:

// The class we are NOT allowed to modify

public class Dog implements IAnimal {

    public String name;
    public int ferocity;

    public Dog(String name, int ferocity) {
        super();
        this.name = name;
        this.ferocity = ferocity;
    }

    @Override
    public String sound() {
        return name + " : \"bark\" (ferocity level:" + ferocity + ")";
    }
}


// The marker interface

public interface AnimalInterface {
}

// The subclass for serialization

public class DogWrapper  extends Dog implements AnimalInterface{

    public DogWrapper(String name, int ferocity) {
        super(name, ferocity);
    }

}

// The subclass for serialization

public class CatWrapper extends Cat implements AnimalInterface{


    public CatWrapper(String name) {
        super(name);
    }
}

সুতরাং, আমরা CatWrapperপরিবর্তে Cat, DogWrapperপরিবর্তে Dogএবং AlternativeAnimalAdapterপরিবর্তে ব্যবহার করবIAnimalAdapter

// The only difference between `IAnimalAdapter` and `AlternativeAnimalAdapter` is that of the interface, i.e, `AnimalInterface` instead of `IAnimal`

public class AlternativeAnimalAdapter implements JsonSerializer<AnimalInterface>, JsonDeserializer<AnimalInterface> {

    private static final String CLASSNAME = "CLASSNAME";
    private static final String INSTANCE  = "INSTANCE";

    @Override
    public JsonElement serialize(AnimalInterface src, Type typeOfSrc,
                                 JsonSerializationContext context) {

        JsonObject retValue = new JsonObject();
        String className = src.getClass().getName();
        retValue.addProperty(CLASSNAME, className);
        JsonElement elem = context.serialize(src); 
        retValue.add(INSTANCE, elem);
        return retValue;
    }

    @Override
    public AnimalInterface deserialize(JsonElement json, Type typeOfT,
            JsonDeserializationContext context) throws JsonParseException  {
        JsonObject jsonObject = json.getAsJsonObject();
        JsonPrimitive prim = (JsonPrimitive) jsonObject.get(CLASSNAME);
        String className = prim.getAsString();

        Class<?> klass = null;
        try {
            klass = Class.forName(className);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            throw new JsonParseException(e.getMessage());
        }
        return context.deserialize(jsonObject.get(INSTANCE), klass);
    }
}

আমরা একটি পরীক্ষা করা:

public class Test {

    public static void main(String[] args) {

        // Note that we are using the extended classes instead of the base ones
        IAnimal animals[] = new IAnimal[]{new CatWrapper("Kitty"), new DogWrapper("Brutus", 5)};
        Gson gsonExt = null;
        {
            GsonBuilder builder = new GsonBuilder();
            builder.registerTypeAdapter(AnimalInterface.class, new AlternativeAnimalAdapter());
            gsonExt = builder.create();
        }
        for (IAnimal animal : animals) {
            String animalJson = gsonExt.toJson(animal, AnimalInterface.class);
            System.out.println("serialized with the custom serializer:" + animalJson);
            AnimalInterface animal2 = gsonExt.fromJson(animalJson, AnimalInterface.class);
        }
    }
}

আউটপুট:

serialized with the custom serializer:{"CLASSNAME":"com.examples_so.CatWrapper","INSTANCE":{"name":"Kitty"}}
serialized with the custom serializer:{"CLASSNAME":"com.examples_so.DogWrapper","INSTANCE":{"name":"Brutus","ferocity":5}}

1

আপনি যদি কোনও টাইপের জন্য একটি টাইপএডাপ্টার এবং তার উপ-প্রকারের জন্য অন্য কোনও পরিচালনা করতে চান তবে আপনি টাইপএডাপ্টার কারখানাটি ব্যবহার করতে পারেন:

public class InheritanceTypeAdapterFactory implements TypeAdapterFactory {

    private Map<Class<?>, TypeAdapter<?>> adapters = new LinkedHashMap<>();

    {
        adapters.put(Animal.class, new AnimalTypeAdapter());
        adapters.put(Dog.class, new DogTypeAdapter());
    }

    @SuppressWarnings("unchecked")
    @Override
    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
        TypeAdapter<T> typeAdapter = null;
        Class<?> currentType = Object.class;
        for (Class<?> type : adapters.keySet()) {
            if (type.isAssignableFrom(typeToken.getRawType())) {
                if (currentType.isAssignableFrom(type)) {
                    currentType = type;
                    typeAdapter = (TypeAdapter<T>)adapters.get(type);
                }
            }
        }
        return typeAdapter;
    }
}

এই কারখানাটি সর্বাধিক নির্ভুল টাইপএডাপ্টার প্রেরণ করবে


0

আপনি যদি মার্কস জুনিয়াস ব্রুটাসের উত্তরটি ব্যবহারকারীর ২২২২২২6363 সম্পাদনার সাথে একত্রিত করেন তবে আপনি আপনার অ্যাডাপ্টারে একটি ইন্টারফেস টাইপের কাজ হিসাবে সংজ্ঞায়িত করে একটি বৃহত শ্রেণির শ্রেণিবিন্যাস নির্দিষ্ট করে এড়াতে পারবেন। তারপরে আপনি আপনার ইন্টারফেসে জেএসএন () এবং জেএসএন () এর ডিফল্ট বাস্তবায়ন সরবরাহ করতে পারেন (যা কেবলমাত্র এই দুটি পদ্ধতি অন্তর্ভুক্ত করে) এবং আপনার ইন্টারফেসটি বাস্তবায়িত করার জন্য প্রতিটি শ্রেণি রয়েছে। Ingালাইয়ের সাথে মোকাবিলা করার জন্য, আপনার সাবক্লাসগুলিতে আপনি JSON () পদ্ধতি থেকে একটি স্ট্যাটিক সরবরাহ করতে পারেন যা আপনার ইন্টারফেসের ধরণ থেকে উপযুক্ত কাস্টিংকে deserializes এবং সম্পাদন করে। এটি আমার জন্য চমত্কারভাবে কাজ করেছে (কেবল হ্যাশম্যাপসযুক্ত ক্লাসিকে সিরিয়ালাইজিং / ডিসরিয়ালাইজেশন সম্পর্কে সাবধানতা অবলম্বন করুন - আপনি যখন আপনার জিএসন নির্মাতাকে তাত্ক্ষণিক করে তুলবেন তখন এটি যুক্ত করুন:

GsonBuilder builder = new GsonBuilder().enableComplexMapKeySerialization();

আশা করি এটি কাউকে কিছু সময় এবং প্রচেষ্টা বাঁচাতে সহায়তা করবে!

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.