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

如何用Retrofit为成功/失败JSON响应创建统一POJO(已解决)

刚好之前也碰到过类似的Retrofit动态响应问题,给你分享两种可行的解决思路,也顺便聊聊你最后采用的修改JSON结构的方案——这其实是更推荐的做法哦!

先说说原问题的场景

你遇到的是典型的动态响应结构问题:请求成功和失败时后端返回的JSON顶层字段不一致:

  • 失败响应:仅包含success: false和errors对象
  • 成功响应:包含success: true、user对象和Token字符串

方案1:不修改后端JSON的处理方式

如果暂时没法调整后端接口,可以用以下两种方式适配:

方式A:用泛型统一响应基类

创建一个包含所有可能字段的基类,利用Gson的特性——不存在的字段会被自动忽略,不会影响解析:

public class ApiResponse<T> {
    private boolean success;
    private Errors errors;
    private T user;
    private String Token;

    // 生成所有字段的Getters和Setters

    public static class Errors {
        private String email;
        // 可以添加其他可能的错误字段,比如password等
        // Getters and Setters
    }
}

然后在Retrofit接口里这样定义:

@POST("your-login-endpoint")
Call<ApiResponse<User>> login(@Body LoginRequest loginRequest);

调用时只需要先判断success字段,再分支处理:

call.enqueue(new Callback<ApiResponse<User>>() {
    @Override
    public void onResponse(Call<ApiResponse<User>> call, Response<ApiResponse<User>> response) {
        if (response.isSuccessful() && response.body() != null) {
            ApiResponse<User> apiResp = response.body();
            if (apiResp.isSuccess()) {
                // 处理成功逻辑:获取user和Token
                User user = apiResp.getUser();
                String token = apiResp.getToken();
            } else {
                // 处理错误逻辑:获取errors信息
                Errors errors = apiResp.getErrors();
                String emailError = errors.getEmail();
            }
        }
    }

    @Override
    public void onFailure(Call<ApiResponse<User>> call, Throwable t) {
        // 处理网络请求失败的情况
    }
});

方式B:自定义Gson反序列化器

如果觉得基类字段太多不够优雅,可以自定义一个解析器,根据success的值动态选择解析内容:

public class ApiResponseDeserializer implements JsonDeserializer<ApiResponse> {
    @Override
    public ApiResponse deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        JsonObject jsonObj = json.getAsJsonObject();
        boolean isSuccess = jsonObj.get("success").getAsBoolean();
        ApiResponse response = new ApiResponse();
        response.setSuccess(isSuccess);

        if (isSuccess) {
            // 解析成功响应的user和Token
            User user = context.deserialize(jsonObj.get("user"), User.class);
            String token = jsonObj.get("Token").getAsString();
            response.setUser(user);
            response.setToken(token);
        } else {
            // 解析失败响应的errors
            Errors errors = context.deserialize(jsonObj.get("errors"), Errors.class);
            response.setErrors(errors);
        }
        return response;
    }
}

然后在构建Retrofit实例时注册这个解析器:

Gson customGson = new GsonBuilder()
        .registerTypeAdapter(ApiResponse.class, new ApiResponseDeserializer())
        .create();

Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("your-base-url")
        .addConverterFactory(GsonConverterFactory.create(customGson))
        .build();

方案2:修改JSON结构(你采用的最优方案)

你最后把响应统一成了包含success、data和errors的结构,这其实是REST API设计中更规范的做法——不管请求成功与否,顶层结构完全一致,只是根据状态填充data或errors字段,这样前端的解析逻辑会非常清晰。

对应的POJO可以这样定义:

public class UnifiedApiResponse {
    private boolean success;
    private Data data;
    private Errors errors;

    // Getters and Setters

    public static class Data {
        private User user;
        private String token;
        // Getters and Setters
    }

    public static class Errors {
        // 按需添加错误字段,比如email、password等
        private String email;
        // Getters and Setters
    }

    public static class User {
        private int id;
        private String fname;
        private String lname;
        private String email;
        private List<String> roles;
        private int activation_state;
        private String date_registered;
        // Getters and Setters
    }
}

之后在Retrofit接口里直接使用Call<UnifiedApiResponse>,调用时的逻辑会非常简洁:判断success后,要么取data里的用户和token,要么取errors里的错误信息,完全不用纠结结构不一致的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 06:55:02