gson反序列化与不同的数据类型

时间:2015-12-14 17:09:11

标签: android gson

我必须用gson解析一个web服务,它有一个与JsonObject有关的键(即Elements):

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

但现在我的模型不再是Serializable ..

  

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

我该怎么办?

谢谢,

2 个答案:

答案 0 :(得分:1)

You have several options:

  1. Use 2 models:

One object

public static class ModelOne implements Serializable {

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

A list

public static class ModelList implements Serializable {

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

And then use one or the other. I assume you know in advance which you are facing, since your accessors depend on that. (you can't call getObjectElement if you have a list, so before calling getObjectElement, you must know that there is only one element)

  1. use transient field

which excludes the field from serialization

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

And call set*** right after the gson parsing.

  1. Use a custom factory. See Gson handle object or array

答案 1 :(得分:1)

这是我最终完成的事情

我用这种方式建立了我的课程:

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的帮助