2016-09-25 5 views
0

Guten Tag meine Kolleginnen und Entwickler genannt,Android Gson AbstractAdapter.serialize nicht (polymorphe Serialisierung)

Ich bin mit Gson lib von Google in meinem Android-App zu kämpfen. Ich versuche, eine Liste von Objekten zu JSON-String zu serialisieren, jedoch ohne Glück. Meine Vererbungshierarchie sieht so aus:

interface IFloorPlanPrimitive 
abstract class FloorPlanPrimitiveBase implements IFloorPlanPrimitive 
class Wall extends FloorPlanPrimitiveBase 
class Mark extends FloorPlanPrimitiveBase 

Ziemlich einfach. Es gibt einige Felder in jeder Klasse. Ich suchte im Internet nach dieser Angelegenheit und fügte diese Adapterklasse hinzu, um das Serialisieren/Deserialisieren zu erleichtern. Derzeit kann ich nicht serialisieren, also konzentrieren wir uns darauf.

public class FloorPlanPrimitiveAdapter implements 
     JsonSerializer<FloorPlanPrimitiveBase>, JsonDeserializer<FloorPlanPrimitiveBase> { 

    @Override 
    public JsonElement serialize(FloorPlanPrimitiveBase src, Type typeOfSrc, JsonSerializationContext context) { 
     JsonObject result = new JsonObject(); 
     result.add("type", new JsonPrimitive(src.getClass().getSimpleName())); 
     result.add("properties", context.serialize(src, src.getClass())); 

     return result; 
    } 

    @Override 
    public FloorPlanPrimitiveBase deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { 
     JsonObject jsonObject = json.getAsJsonObject(); 
     String type = jsonObject.get("type").getAsString(); 
     JsonElement element = jsonObject.get("properties"); 

     try { 
      final String packageName = IFloorPlanPrimitive.class.getPackage().getName(); 
      return context.deserialize(element, Class.forName(packageName + '.' + type)); 
     } catch (ClassNotFoundException cnfe) { 
      throw new JsonParseException("Unknown element type: " + type, cnfe); 
     } 
    } 
} 

Und das ist, wie ich es verwenden:

public String getFloorPlanAsJSon() { 
    GsonBuilder gsonBilder = new GsonBuilder(); 
    gsonBilder.registerTypeAdapter(FloorPlanPrimitiveBase.class, new FloorPlanPrimitiveAdapter()); 
    Gson gson = gsonBilder.create(); 

    List<IFloorPlanPrimitive> floorPlan = mRenderer.getFloorPlan(); 
    String jsonString = gson.toJson(floorPlan); 

    return jsonString; 
} 

Von einem einfachen Debug ich sehe, dass serialize Methode der FloorPlanPrimitiveAdapter nicht aufgerufen werden, wenn die Serialisierung und damit komme ich nicht jene „type“ und "Eigenschaften" Felder in Json. Stattdessen bekomme ich eine direkte Json-Saite. Ich nehme an, das liegt an den unterschiedlichen Typen. Ich möchte IFloorPlanPrimitive serialisieren, aber übergeben Sie FloorPlanPrimitiveBase, die diese Schnittstelle implementiert. Meine Erwartung war, dass es funktionieren sollte :)

Kann jemand darauf hinweisen, wie man in dieser Situation mit Serialisierung und Deserialisierung umgehen? Wie man dieses "Missverhältnis" überwinden kann?

Vielen Dank im Voraus,

Mit freundlichen Grüßen, Greg.

Antwort

0

Guten Tag,

Ich möchte, dass meine Lösung für mein eigenes Problem teilen. Ich hoffe, dass dies für andere hilfreich sein wird. Außerdem würde ich gerne wissen, ob diese Lösung irgendwelche Mängel aufweist.

Also zuerst die Verwendung. Ich habe mir eine andere Antwort zu SO angeschaut (siehe unten). Auch this Ausgabe auf Gson Github war auch hilfreich (insbesondere lernte ich dort einen Typparameter in toJson() Methode zu übergeben:

public String getFloorPlanAsJSon() { 
    GsonBuilder builder = new GsonBuilder(); 

    final Type type = (new TypeToken<List<FloorPlanPrimitiveBase>>() {}).getType(); 
    builder.registerTypeAdapter(type, new FloorPlanAdapter()); 
    Gson gson = builder.create(); 

    List<IFloorPlanPrimitive> floorPlan = mRenderer.getFloorPlan(); 
    String jsonString = gson.toJson(floorPlan, type); 

    return jsonString; 
} 

Und nun die Adapter nahm ich tatsächlich von this SO beantworten (Vorsicht es Fehler in ihm - der Name der Klasse in Json setzen ist Arraylist statt Klasse des Elements).

public class FloorPlanAdapter implements JsonSerializer<List<FloorPlanPrimitiveBase>> { 

    private static final String CLASSNAME = "CLASSNAME"; 
    private static final String INSTANCE = "INSTANCE"; 

    @Override 
    public JsonElement serialize(List<FloorPlanPrimitiveBase> src, Type typeOfSrc, 
           JsonSerializationContext context) { 
     JsonArray array = new JsonArray(); 

     for (FloorPlanPrimitiveBase primitiveBase : src) { 
      JsonObject primitiveJson = new JsonObject(); 

      String className = primitiveBase.getClass().getCanonicalName(); 
      primitiveJson.addProperty(CLASSNAME, className); 

      JsonElement elem = context.serialize(primitiveBase); 
      primitiveJson.add(INSTANCE, elem); 

      array.add(primitiveJson); 
     } 
     return array; 
    } 
} 

wie Sie es alle Objekte sehen können, in List<> Schleifen über und verarbeitet sie wie FloorPlanPrimitiveBaseAdapter in meiner ursprünglichen Frage

Dies ist, wie ich deserialisieren es:

@Override 
public List<FloorPlanPrimitiveBase> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { 
    final String packageName = IFloorPlanPrimitive.class.getPackage().getName(); 
    List<FloorPlanPrimitiveBase> result = new ArrayList<>(); 
    JsonArray jsonArray = json.getAsJsonArray(); 

    for (JsonElement element : jsonArray) { 
     final JsonObject asJsonObject = element.getAsJsonObject(); 
     String className = asJsonObject.get(CLASSNAME).getAsString(); 
     JsonElement serializedInstance = asJsonObject.get(INSTANCE); 

     Class<?> klass; 
     try { 
      klass = Class.forName(packageName + '.' + className); 
      final FloorPlanPrimitiveBase deserializedInstance = context.deserialize(serializedInstance, klass); 
      result.add(deserializedInstance); 
     } catch (ClassNotFoundException e) { 
      e.printStackTrace(); 
     } 
    } 
    return result; 
} 
Verwandte Themen