Gson ile çok biçimlilik


103

Gson ile bir json dizesini seri durumdan çıkarırken sorun yaşıyorum. Bir dizi komut alıyorum. Komut, başlat, durdur veya başka bir komut türü olabilir. Doğal olarak polimorfizmim var ve başlat / durdur komutu komuttan miras kalıyor.

Gson kullanarak onu doğru komut nesnesine nasıl serileştirebilirim?

Görünüşe göre sadece temel türü, bu bildirilen tür ve asla çalışma zamanı türünü alıyorum.


Yanıtlar:


121

Bu biraz geç ama bugün aynı şeyi yapmak zorunda kaldım. Yani, araştırmama dayanarak ve gson-2.0 kullanırken gerçekten registerTypeHierarchyAdapter yöntemini kullanmak istemiyorsunuz , daha çok sıradan olan registerTypeAdapter . Ve türetilmiş sınıflar için örnek oluşturmanıza veya bağdaştırıcı yazmanıza kesinlikle gerek yoktur : türetilmiş sınıfların varsayılan serileştirmesinden memnun olmanız koşuluyla, temel sınıf veya arabirim için yalnızca bir bağdaştırıcı. Her neyse, işte kod (paket ve içe aktarmalar kaldırıldı) ( github'da da mevcuttur ):

Temel sınıf (benim durumumdaki arayüz):

public interface IAnimal { public String sound(); }

Türetilmiş iki sınıf, Cat:

public class Cat implements IAnimal {

    public String name;

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

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

Ve Köpek:

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

Ve Test sınıfı:

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

Test :: main'i çalıştırdığınızda aşağıdaki çıktıyı alırsınız:

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)

Aslında yukarıdakileri registerTypeHierarchyAdapter yöntemini kullanarak da yaptım , ancak bu, Dog'a veya Cat'e başka bir alan eklemek istediğinizde korumak için bir acı olan özel DogAdapter ve CatAdapter serileştirici / seri çözücü sınıflarının uygulanmasını gerektiriyor gibiydi.


5
Class.forName kullanılarak sınıf adlarının serileştirilmesinin ve serileştirmenin (kullanıcı girdisinden) kaldırılmasının bazı durumlarda güvenlik etkileri oluşturabileceğini ve bu nedenle Gson geliştirme ekibi tarafından önerilmez. code.google.com/p/google-gson/issues/detail?id=340#c2
Programcı Bruce

4
Serileştirmede sonsuz bir döngü elde etmemeyi nasıl başardınız, context.serialize (src); bağdaştırıcınızı yeniden çağıracak. Benim benzer kodumda olan buydu.
che javara

6
Yanlış. Bu çözüm işe yaramıyor. Eğer context.serialize'ı herhangi bir şekilde çağırırsanız, sonsuz özyineleme ile sonuçlanırsınız. İnsanların neden kodu gerçekten test etmeden gönderdiğini merak ediyorum. 2.2.1 ile denedim. Açıklanan hata Bkz stackoverflow.com/questions/13244769/...
che JavaRa

4
@MarcusJuniusBrutus Kodunuzu çalıştırdım ve sadece bu özel durumda çalışıyor gibi görünüyor - çünkü bir IAnimal süper arayüz tanımladınız ve IAnimalAdapter onu kullanıyor. Bunun yerine sadece 'Kedi' varsa, sonsuz özyineleme problemini alırsınız. Dolayısıyla bu çözüm genel durumda hala çalışmıyor - yalnızca ortak bir arayüz tanımlayabildiğiniz zaman. Benim durumumda arayüz yoktu, bu yüzden TypeAdapterFactory ile farklı bir yaklaşım kullanmak zorunda kaldım.
che javara

2
Src.getClass () yerine kullanıcı src.getClass (). GetName (). GetCanonicalName (). Bu, kodun iç / iç içe geçmiş sınıflar için de çalışacağı anlamına gelir.
mR_fr0g

13

Gson şu anda basit polimorfik seriyi kaldırma için yapılandırılabileceği bildirilen bir Tür Hiyerarşi Bağdaştırıcısı kaydetme mekanizmasına sahiptir , ancak bir Tür Hiyerarşi Bağdaştırıcısı yalnızca birleşik bir serileştirici / seri çözücü / örnek oluşturucu gibi göründüğü için durumun nasıl olduğunu anlamıyorum. herhangi bir gerçek polimorfik tip kaydı sağlamadan örnek yaratma ayrıntılarını kodlayıcıya bırakma.

Görünüşe göre Gson yakında RuntimeTypeAdapterdaha basit polimorfik serileştirmeye sahip olacak . Daha fazla bilgi için http://code.google.com/p/google-gson/issues/detail?id=231 adresine bakın .

Yeni kullanılması durumunda RuntimeTypeAdaptermümkün değildir ve GSON kullanmam gerek, o zaman sana bir tipi Hiyerarşi Adaptörü olarak veya Tip Adaptörü olarak ya bir özel deserializer kaydederek kendi çözümünüzü rulo gerekecek düşünüyorum. Aşağıda böyle bir örnek var.

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

API'leri değiştirebiliyorsanız, Jackson'ın şu anda nispeten basit polimorfik seriyi kaldırma mekanizmasına sahip olduğunu unutmayın. Ben de bazı örnekler yayınlanmıştır programmerbruce.blogspot.com/2011/05/...
Programcı Bruce

RuntimeTypeAdapterşimdi tamamlandı, ne yazık ki henüz Gson çekirdeğinde gibi görünmüyor. :-(
Jonathan

8

Marcus Junius Brutus'un harika bir cevabı vardı (teşekkürler!). Örneğini genişletmek için, aşağıdaki değişikliklerle adaptör sınıfını tüm nesne türleri için (sadece IAnimal değil) genel hale getirebilirsiniz:

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
....
}

Ve Test Sınıfında:

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

1
Çözümünü uyguladıktan sonra bir sonraki düşüncem tam olarak bunu yapmaktı :-)
David Levy

7

GSON burada bir tür hiyerarşi adaptörünün nasıl tanımlanacağını ve kaydedileceğini gösteren oldukça iyi bir test senaryosuna sahiptir.

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

Bunu kullanmak için şunu yapın:

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

Bağdaştırıcının serileştirme yöntemi, hangi tipin serileştirildiğine dair basamaklı if-else kontrolü olabilir.

    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;

Seri durumdan çıkarma biraz zordur. Birim testi örneğinde, hangi sınıfa serileştirme dışı bırakılacağına karar vermek için tell-tale özniteliklerinin varlığını kontrol eder. Serileştirmekte olduğunuz nesnenin kaynağını değiştirebiliyorsanız, örnek sınıfının adının FQN'sini tutan her örneğe bir 'classType' özniteliği ekleyebilirsiniz. Bu çok fazla nesne yönelimli değil.


4

Google, polimorfizmi işlemek için kendi RuntimeTypeAdapterFactory'yi yayınladı, ancak maalesef bu gson çekirdeğinin bir parçası değil (sınıfı kopyalayıp projenizin içine yapıştırmanız gerekir).

Misal:

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

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

Burada Animal, Dog ve Cat modellerini kullanarak tam bir çalışma örneğini yayınladım.

Sıfırdan yeniden uygulamak yerine bu adaptöre güvenmenin daha iyi olacağını düşünüyorum.


2

Uzun zaman geçti, ancak çevrimiçi olarak gerçekten iyi bir çözüm bulamadım .. İşte @ MarcusJuniusBrutus'un sonsuz özyinelemeyi engelleyen çözümünde küçük bir değişiklik var.

Aynı seriyi kaldırıcıyı saklayın, ancak serileştiriciyi kaldırın -

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

Ardından, orijinal sınıfınızda ile bir alan ekleyin @SerializedName("CLASSNAME"). İşin püf noktası şimdi bunu temel sınıfın yapıcısında başlatmaktır , bu nedenle arayüzünüzü soyut bir sınıf haline getirin.

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

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

Burada sonsuz özyineleme olmamasının nedeni, gerçek çalışma zamanı sınıfını (yani, Dog, IAnimal değil) context.deserialize . Bu, kullandığımız registerTypeAdapterve kullanmadığımız sürece tip adaptörümüzü çağırmayacaktır.registerTypeHierarchyAdapter


2

Güncellenmiş Cevap - Diğer tüm cevapların en iyi kısımları

Çeşitli kullanım durumları için çözümler anlatıyorum ve aynı zamanda sonsuz yineleme sorununu da ele alıyorum

  • Durum 1: Sen sınıfların kontrolünde olan yani, kendi yazmak olsun Cat, Doghem sınıflar hem deIAnimal arayüz. @ Marcus-junius-brutus tarafından sağlanan çözümü kolayca takip edebilirsiniz (en yüksek puan alan cevap)

    Ortak bir temel arayüz varsa sonsuz özyineleme olmayacaktır. IAnimal

    Peki IAnimalya bu ya da benzeri bir arayüzü uygulamak istemiyorsam ?

    Ardından, @ marcus-junius-brutus (en yüksek puan alan cevap) sonsuz bir özyineleme hatası üretecektir. Bu durumda aşağıdaki gibi bir şey yapabiliriz.

    Temel sınıf içinde bir kopya oluşturucu ve aşağıdaki gibi bir sarmalayıcı alt sınıfı oluşturmamız gerekir :

.

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

Ve tür için serileştirici 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;
    }
}

Peki neden bir kopya oluşturucu?

Kopyalama yapıcısını tanımladığınızda, temel sınıf ne kadar değişirse değişsin, sarmalayıcınız aynı rolle devam edecektir. İkinci olarak, eğer bir kopya oluşturucu tanımlamazsak ve basitçe temel sınıfı alt sınıfa ayırmazsak, genişletilmiş sınıf açısından "konuşmamız" gerekir, yani,CatWrapper . Bileşenlerinizin sarmalayıcı türü değil, temel sınıf açısından konuşması oldukça olasıdır.

Kolay bir alternatif var mı?

Elbette, artık Google tarafından tanıtıldı - RuntimeTypeAdapterFactoryuygulama şu şekildedir:

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

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

Burada, "tür" adı verilen bir alan Animalve aynı içerideki değeri Dog"köpek", Cat"kedi" olarak girmeniz gerekir.

Tam örnek: https://static.javadoc.io/org.danilopianini/gson-extras/0.2.1/com/google/gson/typeadapters/RuntimeTypeAdapterFactory.html

  • Durum 2: Sınıfların kontrolü sizde değil . Bir şirkete katılırsınız veya sınıfların önceden tanımlanmış olduğu ve yöneticinizin bunları hiçbir şekilde değiştirmenizi istemediği bir kitaplığı kullanırsınız - Sınıflarınızı alt sınıflara ayırabilir ve ortak bir işaretleme arabirimi uygulamalarını sağlayabilirsiniz (herhangi bir yöntemi olmayan ) gibi AnimalInterface.

    Ör:

.

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

Yani, biz kullanarak olurdu CatWrapperyerine Cat, DogWrapperyerine Dogve AlternativeAnimalAdapteryerineIAnimalAdapter

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

Bir test yapıyoruz:

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

Çıktı:

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

Bir tür için bir TypeAdapter ve onun alt türü için başka birini yönetmek istiyorsanız, aşağıdaki gibi bir TypeAdapterFactory kullanabilirsiniz:

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

Bu fabrika, en doğru TypeAdapter gönderecek


0

Marcus Junius Brutus'un cevabını user2242263'ün düzenlemesiyle birleştirirseniz, adaptörünüzü bir arayüz türü üzerinde çalışıyor olarak tanımlayarak adaptörünüzde büyük bir sınıf hiyerarşisi belirtmek zorunda kalmazsınız. Daha sonra, arayüzünüzde (yalnızca bu iki yöntemi içerir) toJSON () ve fromJSON () varsayılan uygulamalarını sağlayabilir ve arayüzünüzü uygulamak için ihtiyacınız olan her sınıfa sahip olabilirsiniz. Dönüşümle başa çıkmak için, alt sınıflarınızda, arabirim türünüzden uygun dönüştürmeyi kaldırıp gerçekleştiren statik bir fromJSON () yöntemi sağlayabilirsiniz. Bu benim için harika çalıştı (hashmapler içeren sınıfları serileştirme / seriyi kaldırma konusunda dikkatli olun - gson oluşturucunuzu başlattığınızda şunu ekleyin:

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

Umarım bu, birisinin biraz zaman ve emekten tasarruf etmesine yardımcı olur!

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.