ClassCastException带有Retrofit的对象继承

时间:2015-08-28 04:01:40

标签: android gson retrofit

我正在从Asynctask + Loader迁移到Retrofit以获取核心网络。直到我遇到以前没有发生过ClassCastExceptions的情况一直很顺利:

ImagePojo imagePojo = (ImagePojo) mediaPojo; // Error: cannot cast MediaPojo to ImagePojo

这是我在层次结构中的POJO的骨架:

父/通用媒体对象

public class MediaPojo extends CustomObservable implements Parcelable {
    @SerializedName("media_id")
    private String mMid;
    @SerializedName("type")
    private String mType;
    @SerializedName("title")
    public MediaPojo() {
    }

    @Override
    public int describeContents() {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(mNid);
        dest.writeString(mType);
        dest.writeString(mTitle);
    }

    public static final Parcelable.Creator<MediaPojo> CREATOR = new Parcelable.Creator<MediaPojo>() {
        @Override
        public MediaPojo createFromParcel(Parcel source) {
            return new MediaPojo(source);
        }

        @Override
        public MediaPojo[] newArray(int size) {
            return new MediaPojo[size];
        }
    };
...
} 

//定义所有媒体类型共有的字段

视频媒体类型

public class VideoPojo extends MediaPojo implements Parcelable {
    @SerializedName("video_id")
    private String mVid;
    @SerializedName("video_url")
    private String mVideoUrl;
    @SerializedName("thumbnail")
    private String mThumbnail ...
}

图像媒体类型POJO

public class ImagePojo extends MediaPojo implements Parcelable {
    @SerializedName("image_url")
    private String mImageUrl;
    @SerializedName("width")
    private String mImageWidth;
    @SerializedName("height")
    private String mImageHeight
    ...
}

//其他类型:TextPojo,InfoGraphicPojo ...

到目前为止,我在迁移中对POJO所做的唯一更改是添加@SerializedName注释以允许Retrofit自动将JSON字段映射到定义的POJO实例变量。我发现有必要在运行时将通用MediaPojo转换为特定类型的POJO转换,因为我对api.mydomain.com/media的REST调用可以返回代表各种媒体(视频,图像等)的JSON。

有没有办法让Retrofit围绕我现有的对象继承结构工作?或者我可以用Parcelable接口进行序列化吗?

1 个答案:

答案 0 :(得分:2)

是的,问题是gson总是在改装调用中创建类型。您需要提供custom deserializer以根据您的type字段确定对象类型。这是一个可能看起来像的草图。

public class ModiaPojoDeserializer implements JsonDeserializer<Model> {

    private static final String TYPE_FIELD = "type";
    private static final String IMAGE_TYPE = "image";
    private static final String VIDEO_TYPE = "video";

    @Override
    public Model deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        if (json.isJsonObject() && json.getAsJsonObject().has(TYPE_FIELD)) {
            JsonObject jsonObject = json.getAsJsonObject();
            final String type = jsonObject.get(TYPE_FIELD).getAsString();
            if (VIDEO_TYPE.equals(type)) {
                return context.deserialize(json, VideoPojo.class);
            } else if (IMAGE_TYPE.equals(type)) {
                return context.deserialize(json, ImagePojo.class);
            } // ...
            // If you need to deserialize as MediaPojo,
            // deserialize without the current context 
            // or you will infinite loop
            return new Gson().fromJson(json, typeOfT);

        } else {
            // Return a blank object on error, could use null
            return new MediaPojo();
        }
    }
}

然后,您将使用自定义反序列化器使用Gson.Builder创建自定义gson对象 -

 Gson gson = new GsonBuilder()
     .registerTypeAdapter(MediaPojo.class, new MediaPojoDeserializer())
     .create();

然后在创建RestAdapter -

时添加它
RestAdapter restAdapter = new RestAdapter.Builder()
    .setEndpoint("https://api.mydomain.com")
    .setConverter(new GsonConverter(gson))
    .build();