¿Cómo manejar la deserialización con polymorphism?

Tengo una clase como:

public class Barn { String type; Animal animal; } public class Horse extends Animal { } public class Cow extends Animal { } 

y quiero serializar una lista de ellos:

 List barns = new ArrayList(); Barn barn1 = new Barn(); barn1.setType("horse"); barn1.setAnimal(new Horse()); barns.add(barn1); Barn barn2 = new Barn(); barn2.setType("cow"); barn2.setAnimal(new Cow()); barns.add(barn2); ... Group barns = gson.fromJson(serialized); 

Cuando serializo, el tipo de información se perderá para el atributo Animal. ¿Hay alguna forma de que pueda instalar un oyente analizador de alguna manera para poder proporcionar la clase correcta para deserializar como cuando se encuentra cada elemento en la lista? Esa fue la idea detrás del suministro manual de una cadena que describe el tipo de clase.

Gracias

En el código del proyecto Gson, la base es RuntimeTypeAdapter , que según los informes funciona bien para la serialización polimórfica y la deserialización. No creo que haya intentado usarlo todavía. Consulte http://code.google.com/p/google-gson/issues/detail?id=231 para obtener más información. Tenga en cuenta que aún no se ha incluido en ninguna versión de Gson.

Si su uso no se ajusta a sus necesidades, entonces es necesario un procesamiento de deserialización personalizado. El siguiente es uno de estos enfoques, suponiendo que desee utilizar la estructura JSON demostrada. (Tomaría un enfoque algo diferente, si la estructura JSON podría ser diferente).

 import java.lang.reflect.Type; import java.util.HashMap; import java.util.List; import java.util.Map; 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; import com.google.gson.reflect.TypeToken; public class App { public static void main(String[] args) { Barn[] barns = {new Barn(), new Barn()}; barns[0].type = "horse"; barns[0].animal = new Horse(); barns[1].type = "cow"; barns[1].animal = new Cow(); String json = new Gson().toJson(barns); // [{"type":"horse","animal":{}},{"type":"cow","animal":{}}] BarnDeserializer deserializer = new BarnDeserializer("type"); deserializer.registerBarnType("horse", Horse.class); deserializer.registerBarnType("cow", Cow.class); Gson gson = new GsonBuilder().registerTypeAdapter(Barn.class, deserializer).create(); List barns2= gson.fromJson(json, new TypeToken>(){}.getType()); for (Barn barn : barns2) { System.out.println(barn.animal.getClass()); } } } class BarnDeserializer implements JsonDeserializer { String barnTypeElementName; Gson gson; Map> barnTypeRegistry; BarnDeserializer(String barnTypeElementName) { this.barnTypeElementName = barnTypeElementName; gson = new Gson(); barnTypeRegistry = new HashMap<>(); // Java 7 required for this syntax. } void registerBarnType(String barnTypeName, Class animalType) { barnTypeRegistry.put(barnTypeName, animalType); } @Override public Barn deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { JsonObject barnObject = json.getAsJsonObject(); JsonElement animalTypeElement = barnObject.get(barnTypeElementName); Barn barn = new Barn(); barn.type = animalTypeElement.getAsString(); Class animalType = barnTypeRegistry.get(barn.type); barn.animal = gson.fromJson(barnObject.get("animal"), animalType); return barn; } } class Barn {String type; Animal animal;} class Animal {} class Horse extends Animal {} class Cow extends Animal {} 

Puedes usar Gson Fire para esto. El código se vería así:

 GsonFireBuilder builder = new GsonFireBuilder() .registerTypeSelector(Barn.class, new TypeSelector() { @Override public Class getClassForElement(JsonElement readElement) { String type = readElement.getAsJsonObject().get("type").getAsString(); if(type.equals("horse")){ return Horse.class; } else if(type.equals("cow")) { return Cow.class; } else { return null; //returning null will trigger Gson's default behavior } } }); Gson gson = builder.createGson(); 

También estoy interesado en la función y he agregado una solicitud de función a GSon

https://github.com/google/gson/issues/869

Finalmente gson tiene su propia RuntimeTypeAdapterFactory, pero desafortunadamente no es parte de la biblioteca gson core (para usarla debes copiar y pegar la clase en tu proyecto).

Aquí puede encontrar un ejemplo completo de trabajo.