पॉलसन के साथ बहुरूपता


103

मुझे Gson के साथ एक json स्ट्रिंग deserializing में एक समस्या है। मुझे आदेशों की एक सरणी मिलती है। कमांड स्टार्ट, स्टॉप, कुछ अन्य प्रकार की कमांड हो सकती है। स्वाभाविक रूप से मुझे बहुरूपता है, और कमांड से आरंभ / रोकना आदेश है।

मैं इसे सही कमांड ऑब्जेक्ट में कैसे उपयोग कर सकता हूँ?

ऐसा लगता है कि मुझे केवल आधार प्रकार मिलता है, यह घोषित प्रकार है और रनटाइम प्रकार नहीं है।


जवाबों:


120

यह थोड़ी देर की बात है लेकिन मुझे आज भी यही काम करना था। इसलिए, मेरे शोध के आधार पर और जब gson-2.0 का उपयोग कर आप वास्तव में registerTypeHierarchyAdapter विधि का उपयोग नहीं करना चाहते हैं , लेकिन अधिक सांसारिक registerTypeAdapter । और आप निश्चित रूप से ऐसा करने की जरूरत नहीं है instanceofs व्युत्पन्न वर्ग के लिए या लिखने एडेप्टर: निश्चित रूप से प्रदान की आधार वर्ग या अंतरफलक के लिए सिर्फ एक एडाप्टर, कि आप व्युत्पन्न वर्ग के डिफ़ॉल्ट क्रमबद्धता से खुश हैं। वैसे भी, यहाँ कोड (पैकेज और आयात हटा दिया गया है) ( जीथब में भी उपलब्ध है ):

आधार वर्ग (मेरे मामले में इंटरफ़ेस):

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 + ")";
    }
}

IAnimalAdapter:

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)

मैं वास्तव में इसके बाद के संस्करण का उपयोग कर किया है registerTypeHierarchyAdapter विधि भी, लेकिन वह कस्टम DogAdapter और CatAdapter serializer / deserializer वर्ग है जो किसी भी समय आप कुत्ता करने के लिए या बिल्ली के लिए एक और क्षेत्र में जोड़ना चाहते हैं बनाए रखने के लिए परेशान कर सकती हैं को लागू करने की आवश्यकता के लिए लग रहा था।


5
ध्यान दें कि Class.forName का उपयोग करते हुए वर्ग के नाम और डिसेरिएलाइज़ेशन (उपयोगकर्ता इनपुट से) की क्रमिकता कुछ स्थितियों में सुरक्षा निहितार्थ पेश कर सकती है, और इस प्रकार गॉन देव टीम द्वारा हतोत्साहित किया जाता है। code.google.com/p/google-gson/issues/detail?id=340#c2
प्रोग्रामर ब्रूस

4
आपने क्रमांकन में एक अनंत लूप प्राप्त नहीं करने का प्रबंधन कैसे किया, आप संदर्भ कह रहे हैं ।serialize (src); जो आपके एडेप्टर को फिर से लागू करेगा। मेरे समान कोड में यही हुआ है।
che javara

6
गलत। यह समाधान काम नहीं करता है। यदि आप संदर्भ कहते हैं। किसी भी तरह से आप अनंत पुनरावृत्ति को समाप्त करेंगे। मुझे आश्चर्य है कि लोग वास्तव में परीक्षण कोड के बिना पोस्ट क्यों करते हैं। मैंने 2.2.1 के साथ कोशिश की। बग में वर्णित देखें stackoverflow.com/questions/13244769/...
चे javara

4
@MarcusJuniusBrutus मैंने आपका कोड चलाया और ऐसा लगता है कि यह केवल इस विशेष मामले में काम करता है - क्योंकि आपने एक सुपरनिटफेस IAnimal को परिभाषित किया है, और IAnimalAdapter इसका उपयोग करते हैं। यदि आप के बजाय केवल 'कैट' था, तो आपको अनंत पुनरावृत्ति समस्या मिलेगी। तो यह समाधान अभी भी सामान्य मामले में काम नहीं करता है - केवल जब आप एक सामान्य इंटरफ़ेस को परिभाषित करने में सक्षम होते हैं। मेरे मामले में कोई इंटरफ़ेस नहीं था, इसलिए मुझे TypeAdapterFactory के साथ एक अलग दृष्टिकोण का उपयोग करना पड़ा।
चे जावरा '

2
उपयोगकर्ता src.getClass ()। GetName () के बजाय src.getClass ()। GetCanonicalName ()। यह meads कोड आंतरिक / नेस्टेड कक्षाओं के लिए भी काम करेगा।
mR_fr0g

13

Gson के पास वर्तमान में एक प्रकार के पदानुक्रम एडाप्टर को पंजीकृत करने के लिए एक तंत्र है जिसे कथित तौर पर सरल बहुरूपी deserialization के लिए कॉन्फ़िगर किया जा सकता है, लेकिन मैं यह नहीं देखता कि यह कैसा मामला है, जैसा कि एक प्रकार का पदानुक्रम एडाप्टर बस एक संयुक्त serializer / deserializer / उदाहरण निर्माता को प्रतीत होता है, किसी भी वास्तविक बहुरूपी प्रकार के पंजीकरण के बिना, कोडर तक के निर्माण के विवरण को छोड़कर।

ऐसा लगता है कि Gson जल्द ही RuntimeTypeAdapterसरल बहुरूपी deserialization के लिए होगा। अधिक जानकारी के लिए http://code.google.com/p/google-gson/issues/detail?id=231 देखें ।

यदि नए RuntimeTypeAdapterका उपयोग संभव नहीं है, और आप Gson का उपयोग करेंगे, तो मुझे लगता है कि आपको अपना स्वयं का समाधान रोल करना होगा, एक कस्टम डिसेरिएलाइज़र को या तो एक प्रकार का पदानुक्रम एडाप्टर या प्रकार एडाप्टर के रूप में पंजीकृत करना होगा। निम्नलिखित एक ऐसा उदाहरण है।

// 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);
  }
}

यदि आप एपीआई बदल सकते हैं, तो ध्यान दें कि जैक्सन के पास वर्तमान में अपेक्षाकृत सरल बहुरूपी deserialization के लिए एक तंत्र है। मैंने programmerbruce.blogspot.com/2011/05/…
प्रोग्रामर ब्रूस

RuntimeTypeAdapterअब पूरा हो गया है, दुर्भाग्य से यह ऐसा नहीं लगता है कि यह अभी तक गॉन कोर में है। :-(
जोनाथन

8

मार्कस जुनियस ब्रूटस का शानदार जवाब था (धन्यवाद!)। उनके उदाहरण का विस्तार करने के लिए, आप निम्नलिखित विकल्पों के साथ सभी प्रकार की वस्तुओं (न केवल IAnimal) के लिए काम करने के लिए अपने एडेप्टर को सामान्य बना सकते हैं:

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

GSON में एक बहुत अच्छा परीक्षण मामला है जो दिखा रहा है कि एक प्रकार के पदानुक्रम एडाप्टर को कैसे परिभाषित और पंजीकृत किया जाए।

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;

Deserializing थोड़ा हैकी है। यूनिट टेस्ट उदाहरण में, यह बताने के लिए बताता है कि किस वर्ग को किस वर्ग से अलग होना है। यदि आप उस वस्तु के स्रोत को बदल सकते हैं, जिसे आप क्रमबद्ध कर रहे हैं, तो आप प्रत्येक उदाहरण में 'क्लासटेप' विशेषता जोड़ सकते हैं जो उदाहरण वर्ग के नाम का FQN रखता है। यह हालांकि बहुत ही अप्रयुक्त वस्तु है।


4

Google ने बहुरूपता को संभालने के लिए अपना स्वयं का RuntimeTypeAdapterFactory जारी किया है , लेकिन दुर्भाग्य से यह गन्स कोर का हिस्सा नहीं है (आपको अपनी परियोजना के अंदर कक्षा को कॉपी और पेस्ट करना होगा)।

उदाहरण:

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

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

यहां मैंने पशु, कुत्ते और बिल्ली के मॉडल का उपयोग करके इसका एक पूर्ण कार्य करने वाला उदाहरण पोस्ट किया है।

मुझे लगता है कि खरोंच से इसे फिर से लागू करने के बजाय इस एडाप्टर पर भरोसा करना बेहतर है।


2

लंबा समय बीत चुका है, लेकिन मैं ऑनलाइन एक बहुत अच्छा समाधान नहीं खोज सका .. यहाँ @ MarcusJuniusBrutus के समाधान पर एक छोटा सा मोड़ है, जो अनंत पुनरावृत्ति से बचा जाता है।

एक ही डिसइरलाइज़र रखें, लेकिन सीरिज़र को हटा दें -

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();
  }
}

यहां कोई अनंत पुनरावृत्ति नहीं होने का कारण यह है कि हम वास्तविक रनटाइम क्लास (यानी डॉग नहीं IAnimal) को पास करते हैं context.deserialize। जब तक हम उपयोग करते हैं, तब तक यह हमारे प्रकार के एडेप्टर को कॉल नहीं करेगाregisterTypeAdapter और नहींregisterTypeHierarchyAdapter


2

अपडेटेड उत्तर - अन्य सभी उत्तरों के सर्वश्रेष्ठ भाग

मैं विभिन्न उपयोग के मामलों के लिए समाधानों का वर्णन कर रहा हूं और अनंत पुनरावृत्ति समस्या को भी संबोधित करूंगा

  • केस 1: आप कक्षाओं के नियंत्रण में हैं , यानी, आपको अपनी खुद की Cat, Dogकक्षाओं के साथ-साथ लिखने के लिए भी मिलता हैIAnimal इंटरफ़ेस । आप बस @ marcus-junius-brutus (शीर्ष रेटेड उत्तर) द्वारा दिए गए समाधान का पालन कर सकते हैं

    यदि कोई सामान्य आधार इंटरफ़ेस है तो कोई भी अनंत पुनरावृत्ति नहीं होगी IAnimal

    लेकिन, क्या होगा अगर मैं IAnimalया इस तरह के किसी भी इंटरफ़ेस को लागू नहीं करना चाहता ?

    फिर, @ marcus-junius-brutus (शीर्ष रेटेड उत्तर) एक अनंत पुनरावृत्ति त्रुटि पैदा करेगा। इस मामले में, हम नीचे जैसा कुछ कर सकते हैं।

    हमें बेस क्लास के अंदर एक कॉपी कंस्ट्रक्टर बनाना होगा और एक रैपर सबक्लास निम्नानुसार होगा:

// 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। यह काफी संभव है कि आपके घटक बेस क्लास के संदर्भ में बात करते हैं न कि आवरण प्रकार के।

क्या कोई आसान विकल्प है?

ज़रूर, यह अब Google द्वारा पेश किया गया है - यह 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/RuntimeTypeAdapterFactory.html

  • केस 2: आप कक्षाओं के नियंत्रण में नहीं हैं । आप एक कंपनी में शामिल होते हैं या एक पुस्तकालय का उपयोग करते हैं जहां कक्षाएं पहले से ही परिभाषित हैं और आपका प्रबंधक आपको किसी भी तरह से उन्हें बदलना नहीं चाहता है - आप अपनी कक्षाओं को उप-वर्ग कर सकते हैं और उन्हें एक सामान्य मार्कर इंटरफ़ेस लागू कर सकते हैं (जिसमें कोई विधि नहीं है ) जैसे 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

यदि आप एक प्रकार और उसके उप प्रकार के लिए एक अन्य प्रकार के लिए एक AdAdapter प्रबंधन करना चाहते हैं, तो आप इस तरह TypeAdapterFactory का उपयोग कर सकते हैं:

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

यदि आप उपयोगकर्ता के 2242263 एडिट के साथ मार्कस जुनियस ब्रूटस के उत्तर को जोड़ते हैं, तो आप अपने एडॉप्टर को इंटरफ़ेस प्रकार पर काम करने के रूप में परिभाषित करके अपने एडेप्टर में एक बड़े वर्ग के पदानुक्रम को निर्दिष्ट करने से बच सकते हैं। इसके बाद आप अपने इंटरफ़ेस में toJSON () और fromJSON () में डिफ़ॉल्ट कार्यान्वयन प्रदान कर सकते हैं (जिसमें केवल ये दो विधियाँ शामिल हैं) और आपके इंटरफ़ेस को कार्यान्वित करने के लिए हर वर्ग की आवश्यकता है। कास्टिंग से निपटने के लिए, अपने उपवर्गों में आप एक स्थिरJJSON () विधि प्रदान कर सकते हैं जो आपके इंटरफ़ेस प्रकार से उपयुक्त कास्टिंग करता है और निष्पादित करता है। इसने मेरे लिए शानदार काम किया (बस हैशमैप्स को शामिल करने वाले / deserializing वर्गों के बारे में सावधान रहें - जब आप अपने गन्स बिल्डर को तत्काल भेज दें:

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

आशा है कि यह किसी को कुछ समय और प्रयास बचाने में मदद करता है!

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.