2016-09-25 5 views
0

Добрый день мои коллеги-разработчики,Android gson AbstractAdapter.serialize не называется (полиморфный сериализации)

я борюсь с gson экспромты из Google в своем Android приложение. Я пытаюсь сериализовать список объектов в строку Json, однако без везения. Моя иерархия наследования выглядит так:

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

Довольно просто. В каждом классе есть несколько полей. Я искал этот вопрос в Интернете и добавил этот класс адаптера для упрощения сериализации/десериализации. В настоящее время я не могу сериализоваться, поэтому давайте сосредоточимся на этом.

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

И это, как я использую его:

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

От простой отладки я вижу, что serialize метод FloorPlanPrimitiveAdapter не вызывается при сериализации и, таким образом, я не получаю эти «типа» и "свойства" в Json. Вместо этого я получаю прямолинейную строку Json. Я полагаю, это связано с несоответствием типов. Я прошу сериализовать IFloorPlanPrimitive, но вместо этого передаю FloorPlanPrimitiveBase, который реализует этот интерфейс. Я ожидал, что он должен работать :)

Может ли кто-нибудь указать, как бороться с сериализацией и десериализацией в этой ситуации? Как преодолеть это «несоответствие»?

Спасибо заранее,

С уважением, Грег.

ответ

0

Добрый день,

Я хочу поделиться своим решением с моей проблемой. Надеюсь, это будет полезно для других. Кроме того, я хотел бы знать, есть ли у этого решения какие-либо недостатки.

Итак, сначала использование. Я просмотрел еще один ответ на SO (связанный ниже). Также this вопрос о Gson GitHub также полезно (в частности, я узнал, что передать параметр типа в toJson() метод:

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

И теперь Adapter я на самом деле взял из this SO ответа (остерегайтесь имеет ошибку в нем - название класса введен в Json является ArrayList вместо класса элемента):.

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

Как вы можете видеть, что перебирает все объекты в List<> и обрабатывает его так же, как FloorPlanPrimitiveBaseAdapter в моем оригинальный вопрос

Вот как я десериализую это:

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