【问题标题】:gson deserialisation with differents data types不同数据类型的 gson 反序列化
【发布时间】:2015-12-14 17:09:11
【问题描述】:

我必须用 gson 解析一个 web 服务,该服务有一个有时与 JsonObject(即元素)相关联的键:

"elements": {
   "sheets": 1,
   "questions": 6
}

有时使用数组...

"elements": [
    {
       "_id": "51824208fbca3b0398c8374a",
       "collection": "medias",
       "name": "Document Powerpoint",
       "customNameInModule": true
    },
    {....}
]

所以在包含此元素的模型中,我必须使用 JsonElement 键入它。

@SerializedName("elements")
@Expose
private JsonElement elements;

我的想法是这样构建我的访问器:

private List < Element > listElement;

public List < Element > getListElements() {
    if (listElement == null) {
        Type listType = (new TypeToken < List < Element >> () {}).getType();
        listElement = (new Gson()).fromJson(elements.toString(), listType);
        return listElement;
    } else {
        return listElement;
    }
}

private ElementsObject objectElement;

public ElementsObject getObjectElement() {
    if (objectElement == null) {
        objectElement = (new Gson()).fromJson(elements.toString(), ElementsObject.class);
        return objectElement;
    } else {
        return objectElement;
    }
}

但现在我的模型不再是可序列化的..

java.lang.RuntimeException: Parcelable遇到IOException写 可序列化对象

我该怎么办?

谢谢,

【问题讨论】:

  • 你需要对做这个网络服务的人大喊大叫,直到他们把它改成有意义的东西。
  • 这个:stackoverflow.com/questions/14582440/…? (另外,当反序列化结束时,将 json 对象的实际内容保存到对象的字段中)
  • 这是一个复杂的 javascript 客户端使用的 Web 服务,更改它的成本很高。但我同意你的观点,不幸的是我没有看到它开始
  • 哦,我的不可序列化异常?
  • 在我的代码中究竟什么是不可序列化的我完全不明白为什么不

标签: android gson


【解决方案1】:

您有多种选择:

  1. 使用 2 个模型:

一个对象

public static class ModelOne implements Serializable {

    @Expose
    @SerializedName("elements")
    ElementsObject element;
}

列表

public static class ModelList implements Serializable {

    @Expose
    @SerializedName("elements")
    List<ElementsObject> elements;
}

然后使用其中一个。我假设您事先知道您所面临的,因为您的访问者依赖于此。 (如果有列表就不能调用getObjectElement,所以在调用getObjectElement之前要知道元素只有一个)

  1. 使用transient字段

从序列化中排除字段

public static class ModelTransient implements Serializable {

    @Expose
    @SerializedName("elements")
    transient JsonElement elements;

    private List < Element > listElement;
    private ElementsObject objectElement;

    public void setListElements() {
        Type listType = (new TypeToken < List < Element >> () {}).getType();
        listElement = (new Gson()).fromJson(elements.toString(), listType);
    }

    public List < Element > getListElements() {
        return listElement;
    }


    public void setObjectElement() {
        objectElement = (new Gson()).fromJson(elements.toString(), ElementsObject.class);
    }

    public ElementsObject getObjectElement() {
        return objectElement;
    }
}

并在 gson 解析后立即调用 set***

  1. 使用自定义工厂。见Gson handle object or array

【讨论】:

  • 你觉得我的解决方案怎么样?
【解决方案2】:

这是我最终完成的工作

我以这种方式构建了我的课程:

public class CourseElement implements Serializable{

    private CourseElementDeserializationType type;

    public CourseElementDeserializationType getType() {
        return type;
    }

    private List<Element> listElement;
    private ElementsObject objectElement;


    public CourseElement(List<Element> listElement) {
        type = CourseElementDeserializationType.ARRAY;
        this.listElement = listElement;
    }

    public CourseElement(ElementsObject objectElement){
        type = CourseElementDeserializationType.OBJECT;
        this.objectElement = objectElement;
    }


    public List<Element> getListElements() {
        return listElement;
    }

    public ElementsObject getObjectElement() {
        return objectElement;
    }
}

我还构建了一个类型转换器:

public class CourseElementTypeConverter implements JsonSerializer<CourseElement>, JsonDeserializer<CourseElement> {
    // No need for an InstanceCreator since DateTime provides a no-args constructor

    @Override
    public JsonElement serialize(CourseElement src, Type srcType, JsonSerializationContext context) {
        switch (src.getType()) {
            case ARRAY:
                Type listType = (new TypeToken<List<Element>>() {
                }).getType();
                return new JsonPrimitive((new Gson()).toJson(src.getListElements(), listType));
            case OBJECT:
                return new JsonPrimitive((new Gson()).toJson(src.getObjectElement(), ElementsObject.class));
            default:
                return null;
        }
    }

    @Override
    public CourseElement deserialize(JsonElement json, Type type, JsonDeserializationContext context)
            throws JsonParseException {

        CourseElementDeserializationType courseType;
        if (json.isJsonArray()) {
            courseType = CourseElementDeserializationType.ARRAY;
        } else {
            courseType = CourseElementDeserializationType.OBJECT;
        }

        switch (courseType) {
            case ARRAY:
                Type listType = (new TypeToken<List<Element>>() {
                }).getType();
                List<Element> list = (new Gson()).fromJson(json, listType);
                return new CourseElement(list);
            case OBJECT:
                return new CourseElement((new Gson()).fromJson(json, ElementsObject.class));
            default:
                return null;
        }
    }
}

以及我在改造中使用的 json 构建器:

GsonBuilder gsonBuilder = new GsonBuilder();
        gsonBuilder.registerTypeAdapter(DateTime.class, new DateTimeTypeConverter());
        gsonBuilder.registerTypeAdapter(CourseElement.class, new CourseElementTypeConverter());
        Gson gson = gsonBuilder.create();

非常感谢 njzk2 的帮助

【讨论】:

  • 看起来不错。您可以将所有与 Json 相关的内容移至转换器(例如,模型中有 2 个构造函数,一个带有 Object,一个带有 List)以避免弄乱您的模型。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-26
相关资源
最近更新 更多