如何用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
相关产品推荐
相关产品推荐

