Android Utiliser Gson avec héritage


Exemple

Gson ne supporte pas l'héritage par défaut.

Disons que nous avons la hiérarchie de classes suivante:

public class BaseClass {
    int a;
 
    public int getInt() {
        return a;
   }
}
 
public class DerivedClass1 extends BaseClass {
     int b;
 
     @Override
     public int getInt() {
         return b;
     }
 }
 
public class DerivedClass2 extends BaseClass {
    int c;
 
    @Override
    public int getInt() {
        return c;
    }
}

Et maintenant, nous voulons sérialiser une instance de DerivedClass1 en une chaîne JSON

DerivedClass1 derivedClass1 = new DerivedClass1();
derivedClass1.b = 5;
derivedClass1.a = 10;
 
Gson gson = new Gson();
String derivedClass1Json = gson.toJson(derivedClass1);

Maintenant, à un autre endroit, nous recevons cette chaîne json et souhaitons la désérialiser - mais au moment de la compilation, nous savons seulement qu’elle est supposée être une instance de BaseClass :

BaseClass maybeDerivedClass1 = gson.fromJson(derivedClass1Json, BaseClass.class);
System.out.println(maybeDerivedClass1.getInt());

Mais GSON ne sait pas que: derivedClass1Json était à l'origine une instance de DerivedClass1 , donc cela imprimera 10.

Comment résoudre ce problème?

Vous devez créer votre propre JsonDeserializer , qui gère de tels cas. La solution n'est pas parfaitement propre, mais je n'ai pas pu en trouver une meilleure.

Tout d'abord, ajoutez le champ suivant à votre classe de base

@SerializedName("type")
private String typeName;

Et l'initialiser dans le constructeur de la classe de base

public BaseClass() {
    typeName = getClass().getName();
}

Ajoutez maintenant la classe suivante:

public class JsonDeserializerWithInheritance<T> implements JsonDeserializer<T> {
 
 @Override
 public T deserialize(
     JsonElement json, Type typeOfT, JsonDeserializationContext context)
     throws JsonParseException {
     JsonObject jsonObject = json.getAsJsonObject();
     JsonPrimitive classNamePrimitive = (JsonPrimitive) jsonObject.get("type");
 
     String className = classNamePrimitive.getAsString();
 
     Class<?> clazz;
     try {
     clazz = Class.forName(className);
     } catch (ClassNotFoundException e) {
     throw new JsonParseException(e.getMessage());
     }
     return context.deserialize(jsonObject, clazz);
 }
}

Tout ce qui reste à faire est de tout brancher -

GsonBuilder builder = new GsonBuilder();
 builder
 .registerTypeAdapter(BaseClass.class, new JsonDeserializerWithInheritance<BaseClass>());
 Gson gson = builder.create();

Et maintenant, en exécutant le code suivant

 DerivedClass1 derivedClass1 = new DerivedClass1();
 derivedClass1.b = 5;
 derivedClass1.a = 10;
 String derivedClass1Json = gson.toJson(derivedClass1);
 
 BaseClass maybeDerivedClass1 = gson.fromJson(derivedClass1Json, BaseClass.class);
 System.out.println(maybeDerivedClass1.getInt());

Imprimera 5.