Réponse actualisée - Meilleures parties de toutes les autres réponses
Je décris des solutions pour différents cas d'utilisation et j'aborderai les questions suivantes récursion infinie problème également
-
Cas 1 : Vous avez le contrôle des cours c'est-à-dire que vous devez écrire votre propre Cat
, Dog
ainsi que les classes IAnimal
l'interface. Vous pouvez simplement suivre la solution fournie par @marcus-junius-brutus (la réponse la mieux notée).
Il n'y aura pas de récursion infinie s'il y a une interface de base commune comme IAnimal
Mais, que se passe-t-il si je ne veux pas implémenter le IAnimal
ou toute autre interface de ce type ?
Ensuite, @marcus-junius-brutus (la réponse la mieux notée) produira une erreur de récursion infinie. Dans ce cas, nous pouvons faire quelque chose comme ci-dessous.
Nous devrions créer un constructeur de copie à l'intérieur de la classe de base et d'une sous-classe wrapper comme suit :
.
// 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);
}
}
Et le sérialiseur pour le type 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;
}
}
Alors, pourquoi un constructeur de copie ?
Eh bien, une fois que vous définissez le constructeur de copie, peu importe combien la classe de base change, votre wrapper continuera avec le même rôle. Deuxièmement, si nous ne définissons pas de constructeur de copie et que nous nous contentons de sous-classer la classe de base, nous devrons "parler" en termes de classe étendue, à savoir CatWrapper
. Il est tout à fait possible que vos composants parlent en termes de classe de base et non de type de wrapper.
Existe-t-il une alternative facile ?
Bien sûr, elle a maintenant été introduite par Google - c'est la RuntimeTypeAdapterFactory
mise en œuvre :
RuntimeTypeAdapterFactory<Animal> runtimeTypeAdapterFactory = RuntimeTypeAdapterFactory
.of(Animal.class, "type")
.registerSubtype(Dog.class, "dog")
.registerSubtype(Cat.class, "cat");
Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(runtimeTypeAdapterFactory)
.create();
Dans ce cas, vous devez introduire un champ appelé "type" dans la base de données de l'entreprise. Animal
et la valeur de la même à l'intérieur Dog
pour être "chien", Cat
pour être "chat"
Exemple complet : https://static.javadoc.io/org.danilopianini/gson-extras/0.2.1/com/google/gson/typeadapters/RuntimeTypeAdapterFactory.html
.
// 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);
}
}
Donc, nous utiliserions CatWrapper
au lieu de Cat
, DogWrapper
au lieu de Dog
y AlternativeAnimalAdapter
au lieu de 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);
}
}
Nous effectuons un test :
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);
}
}
}
Sortie :
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}}
0 votes
stackoverflow.com/q/19588020/3315914