如何用Retrofit处理随用户类型变化的登录API响应格式?
这是个很常见的API响应多态场景,我给你几个实用的解决方案,你可以根据自己的需求来选:
方案一:单一Model类兼容两种用户类型
这种方式最简单,直接在现有的User类里添加type=4对应的字段即可。因为Gson在反序列化时会自动忽略JSON里不存在的字段,所以不会有冲突。
代码示例:
public class LoginResponse { @SerializedName("type") public int type; @SerializedName("user") public User user; public static class User { // 原有的学生用户字段 @SerializedName("stud_id") public int stud_id; @SerializedName("stud_reference_id") public String stud_reference_id; // 新增的协调员用户字段 @SerializedName("coord_id") public int coord_id; @SerializedName("coord_login_id") public int coord_login_id; @SerializedName("coord_name") public String coord_name; } }
使用时,只需要根据type字段判断要使用哪些属性:
// 反序列化JSON LoginResponse response = new Gson().fromJson(jsonString, LoginResponse.class); if (response.type == 2) { // 处理学生用户逻辑,比如使用stud_id、stud_reference_id System.out.println("学生ID:" + response.user.stud_id); } else if (response.type == 4) { // 处理协调员用户逻辑,比如使用coord_id、coord_name System.out.println("协调员姓名:" + response.user.coord_name); }
优点:实现快,代码改动最小;缺点:字段混杂,后续扩展更多用户类型时会越来越臃肿。
方案二:拆分不同的User子类(更规范的面向对象方案)
如果追求代码的整洁性和可扩展性,建议把不同类型的用户拆分成独立的子类,配合自定义反序列化器来匹配对应的类型。
第一步:定义父类和子类
public class LoginResponse { @SerializedName("type") public int type; @SerializedName("user") public User user; // 抽象父类User,可添加公共字段(如果有) public static abstract class User {} // 学生用户子类 public static class StudentUser extends User { @SerializedName("stud_id") public int stud_id; @SerializedName("stud_reference_id") public String stud_reference_id; } // 协调员用户子类 public static class CoordinatorUser extends User { @SerializedName("coord_id") public int coord_id; @SerializedName("coord_login_id") public int coord_login_id; @SerializedName("coord_name") public String coord_name; } }
第二步:编写自定义反序列化器
这个反序列化器会根据type字段的值,决定把user反序列化成哪个子类:
public class LoginResponseDeserializer implements JsonDeserializer<LoginResponse> { @Override public LoginResponse deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { JsonObject jsonObject = json.getAsJsonObject(); int userType = jsonObject.get("type").getAsInt(); LoginResponse response = new LoginResponse(); response.type = userType; // 根据type选择对应的User子类反序列化 JsonElement userJson = jsonObject.get("user"); if (userType == 2) { response.user = context.deserialize(userJson, LoginResponse.StudentUser.class); } else if (userType == 4) { response.user = context.deserialize(userJson, LoginResponse.CoordinatorUser.class); } else { // 处理未知用户类型的情况,比如抛出异常或返回默认对象 throw new JsonParseException("未知的用户类型:" + userType); } return response; } }
第三步:注册并使用反序列化器
在创建Gson实例时注册这个自定义反序列化器:
Gson gson = new GsonBuilder() .registerTypeAdapter(LoginResponse.class, new LoginResponseDeserializer()) .create(); LoginResponse response = gson.fromJson(jsonString, LoginResponse.class); // 使用时强转成对应的子类 if (response.type == 2) { LoginResponse.StudentUser student = (LoginResponse.StudentUser) response.user; // 操作学生字段 } else if (response.type == 4) { LoginResponse.CoordinatorUser coordinator = (LoginResponse.CoordinatorUser) response.user; // 操作协调员字段 }
优点:代码结构清晰,字段互不干扰,后续新增用户类型只需添加新子类并修改反序列化器;缺点:需要额外编写反序列化器,代码量稍大。
总结
- 如果你的用户类型较少、字段不多,方案一是最快捷的选择;
- 如果后续可能扩展更多用户类型,或者追求代码规范,方案二更合适。
内容的提问来源于stack exchange,提问作者AFLAH ALI
相关产品推荐
相关产品推荐

