【问题标题】:ClassCastException Object Inheritance with RetrofitClassCastException 对象继承与改造
【发布时间】:2015-08-28 04:01:39
【问题描述】:

我正在从 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 实例变量。我发现有必要在运行时对特定类型的 POJO 进行通用 MediaPojo 转换,因为我对 api.mydomain.com/media 的 REST 调用可以返回表示各种类型(视频、图像等)媒体的 JSON。

有什么方法可以让 Retrofit 围绕我已经存在的对象继承结构工作?或者它可以像我使用 Parcelable 接口进行序列化的方式一样吗?

【问题讨论】:

    标签: android gson retrofit


    【解决方案1】:

    是的,问题是 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();
    

    【讨论】:

    • 太棒了。我想不需要对称序列化?如中,如果我们创建自定义反序列化器,我们不需要创建自定义序列化器?
    • 正确,不需要。如果您不指定一个并且只指定一个自定义的脱轨器,它将使用默认序列化。默认序列化应该适合您的情况。
    猜你喜欢
    • 2014-12-27
    • 1970-01-01
    • 2018-05-12
    • 1970-01-01
    • 2023-03-19
    • 1970-01-01
    • 1970-01-01
    • 2011-04-02
    • 2015-11-28
    相关资源
    最近更新 更多