You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Retrofit2处理Api多响应时出现类型转换异常问题

解决Retrofit回调中ClassCastException(LinkedTreeMap转自定义POJO失败)

我看你遇到的问题是Retrofit调用API后,明明日志里能打印出成功的响应,但判断response.body() instanceof OtpSuccessResponse却不生效,还抛出了ClassCastException——这是因为你用了Call<Object>作为请求类型,Gson没办法知道要把JSON解析成你的OtpSuccessResponse类,只能默认转成LinkedTreeMap来存储键值对,自然过不了instanceof的判断,强转就报错了。

下面给你两种可行的解决方案:

方案一:使用通用响应类(推荐)

创建一个包含成功和失败所有字段的通用响应类,这样Retrofit可以直接解析成这个类,然后通过status字段来区分处理:

第一步:定义通用响应POJO

public class OtpResponse {
    @SerializedName("status")
    @Expose
    private String status;
    @SerializedName("message")
    @Expose
    private String message;
    @SerializedName("token")
    @Expose
    private String token;
    @SerializedName("subscription_active")
    @Expose
    private String subscriptionActive;
    @SerializedName("errors")
    @Expose
    private List<String> errors;

    // 生成所有字段的getter方法,方便后续取值
    public String getStatus() { return status; }
    public String getMessage() { return message; }
    public String getToken() { return token; }
    public String getSubscriptionActive() { return subscriptionActive; }
    public List<String> getErrors() { return errors; }
}

第二步:修改Retrofit请求和回调

把Call<Object>改成Call<OtpResponse>,然后在回调里根据status判断是成功还是失败:

Call<OtpResponse> call = jsonApi.hitOtp(otpPost);
call.enqueue(new Callback<OtpResponse>() {
    @Override
    public void onResponse(Call<OtpResponse> call, Response<OtpResponse> response) {
        Log.d(TAG, "onResponse: "+response.body());
        OtpResponse otpResponse = response.body();
        if(otpResponse != null){
            // 假设成功时status是"success",根据你的实际API返回值调整
            if("success".equals(otpResponse.getStatus())){
                Toast.makeText(OtpActivity.this, otpResponse.getMessage(), Toast.LENGTH_SHORT).show();
                // 这里可以直接获取token和subscription_active
                String token = otpResponse.getToken();
                String isActive = otpResponse.getSubscriptionActive();
            } else if("failed".equals(otpResponse.getStatus())){
                Toast.makeText(OtpActivity.this, otpResponse.getMessage(), Toast.LENGTH_SHORT).show();
                // 处理错误列表
                List<String> errors = otpResponse.getErrors();
            }
        }
    }

    @Override
    public void onFailure(Call<OtpResponse> call, Throwable t) {
        Log.d(TAG, "onFailure: "+t.getMessage());
    }
});

方案二:手动解析ResponseBody

如果不想用通用类,可以让Retrofit返回ResponseBody,然后手动用Gson解析成对应的POJO:

第一步:定义失败响应POJO

先给失败的响应也创建一个POJO类:

public class OtpFailureResponse {
    @SerializedName("status")
    @Expose
    private String status;
    @SerializedName("message")
    @Expose
    private String message;
    @SerializedName("errors")
    @Expose
    private List<String> errors;

    public String getMessage() { return message; }
    public List<String> getErrors() { return errors; }
}

第二步:修改请求和回调逻辑

把请求改成Call<ResponseBody>,然后在回调里手动解析JSON:

Call<ResponseBody> call = jsonApi.hitOtp(otpPost);
call.enqueue(new Callback<ResponseBody>() {
    @Override
    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
        try {
            if(response.body() == null) return;
            String jsonResponse = response.body().string();
            Log.d(TAG, "onResponse: "+jsonResponse);
            
            // 先解析status字段判断响应类型
            JsonObject jsonObj = new JsonParser().parse(jsonResponse).getAsJsonObject();
            String status = jsonObj.get("status").getAsString();
            
            if(!"failed".equals(status)){
                // 解析成成功响应类
                OtpSuccessResponse successRes = new Gson().fromJson(jsonResponse, OtpSuccessResponse.class);
                Toast.makeText(OtpActivity.this, successRes.getMessage(), Toast.LENGTH_SHORT).show();
            } else {
                // 解析成失败响应类
                OtpFailureResponse failureRes = new Gson().fromJson(jsonResponse, OtpFailureResponse.class);
                Toast.makeText(OtpActivity.this, failureRes.getMessage(), Toast.LENGTH_SHORT).show();
            }
        } catch (IOException e) {
            e.printStackTrace();
            Toast.makeText(OtpActivity.this, "解析响应失败", Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    public void onFailure(Call<ResponseBody> call, Throwable t) {
        Log.d(TAG, "onFailure: "+t.getMessage());
    }
});

为什么原来的代码会报错?

当你使用Call<Object>时,Retrofit的Gson转换器没有收到明确的目标类型信息,它会把JSON对象默认转换成LinkedTreeMap(Gson用来存储无类型JSON对象的默认实现),所以response.body()实际是LinkedTreeMap的实例,不是你定义的OtpSuccessResponse,这就导致instanceof判断返回false,如果你后续尝试强转就会抛出ClassCastException。

内容的提问来源于stack exchange,提问作者Vivek Negi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 19:07:49