【问题标题】:Android gson AbstractAdapter.serialize is not called (polymorphic serialization)Android gson AbstractAdapter.serialize 不被调用(多态序列化)
【发布时间】:2016-09-25 12:04:03
【问题描述】:

各位开发者,你们好,

我在我的 Android 应用程序中使用来自 google 的 gson lib 苦苦挣扎。我正在尝试将对象列表序列化为 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;
}

从一个简单的调试中我看到FloorPlanPrimitiveAdapterserialize 方法在序列化时没有被调用,因此我在Json 中没有得到那些“类型”和“属性”字段。相反,我得到了直接的 Json 字符串。我想这是由于类型不匹配。我要求序列化IFloorPlanPrimitive,而是传递实现此接口的FloorPlanPrimitiveBase。我的期望是它应该工作:)

谁能指出在这种情况下如何处理序列化和反序列化?如何克服这种“不匹配”?

提前谢谢你,

亲切的问候,格雷格。

【问题讨论】:

    标签: android json serialization polymorphism


    【解决方案1】:

    早安,

    我想分享我对自己问题的解决方案。我希望这对其他人有帮助。另外,我想知道这个解决方案是否有任何缺陷。

    所以,首先是用法​​。我查看了关于 SO 的另一个答案(链接如下)。 Gson github上的this问题也很有帮助(特别是我在那里学会了将类型参数传递给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&lt;&gt; 中的所有对象,并像我原来的问题中的 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;
    }
    

    【讨论】:

      猜你喜欢
      • 2012-10-26
      • 2023-04-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-17
      • 1970-01-01
      相关资源
      最近更新 更多