我有一个REST服务,它的响应可以根据状态进行更改。例如;当我发送请求时,响应可以是两种类型。像这样的第一个
{
"status": "success",
"user": {
"user_id": 3554,
"full_name": "test",
"email_address": "test@test1.com",
"end_date": null
}
}
第二种就是这样
{
"status": "failure",
"reason": "email_taken"
}
根据响应附带的“状态”进行响应。我搜索了此问题并找到了一些解决方案(自定义转换器,设置自定义转换器等),但我认为这些还不够清楚。有什么解决办法吗?如果“状态”成功,则将JSON响应转换为User模型,否则将json响应转换为FailureModel?
改装依赖项:实现'com.squareup.retrofit:retrofit:1.9.0'
如果唯一的解决方案是自定义转换器,请清楚地解释一下,因为我在这个主题上真的很陌生。
答案 0 :(得分:1)
您可以使用唯一的模型并使用它来处理两种情况:
public class UserResponseModel{
private String status;
private String reason;
private UserModel user;
// getter/setter
boolean isFailure(){
return status == "failure"
}
boolean isSuccess(){
return status == "success"
}
}
您可以这样做
UserResponseModel response
if( response.isSuccess() ) // do whatever with response.user
else // do whatever with response.reason
答案 1 :(得分:1)
使用自定义json解串器是可能的。如果状态不是成功,则只有状态为成功时才具有用户。如果您遇到状态错误,请尝试访问其null。
public class CustomConvertor implements JsonDeserializer<Response> {
@Override
public Response deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
Gson gson = new Gson();
Response response = gson.fromJson(json, Response.class);
if (response.getStatus().equals("success")) {
// The full response as a json object
final JsonObject jsonObject = json.getAsJsonObject();
// The user attribute in the JSON received
final JsonElement jsonElement = jsonObject.get("user");
User user = gson.fromJson(jsonElement, User.class);
response.setUser(user);
}else{
// you could do this
// not needed as json is deserialized to Response already
// just for the example
final JsonObject jsonObject = json.getAsJsonObject();
String reason = jsonObject.getAsJsonPrimitive("reason").getAsString();
response.setReason(reason);
}
return response;
}
}
改造部分
GsonBuilder gsonBuilder =new GsonBuilder();
gsonBuilder.registerTypeAdapter(Response.class, new CustomConvertor());
Gson gson = gsonBuilder.create();
GsonConverterFactory gsonConverterFactory = GsonConverterFactory.create(gson);
Retrofit retrofit = new Retrofit.Builder()
...// other setups
.addConverterFactory(gsonConverterFactory).build();
然后
// service is my case
Service service = retrofit.create(Service.class);
// call enqueue in your case.for testing i used mockwebserver
Response response = service.exampleJson().execute().body();
Log.i("User: ","" + response.geUser().getFullname());
如果发生错误
Log.i("Error: ","" + response.getReason());
您可以从http://www.jsonschema2pojo.org/那里获得声波
Pojo的
Response.java
public class Response {
@SerializedName("status")
@Expose
private String status;
@SerializedName("user")
@Expose
private User user;
@Expose
@SerializedName("reason")
private String reason;
public void setReason(String reason) {
this.reason = reason;
}
public String getReason() {
return reason;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
User.java
public class User {
@SerializedName("user_id")
@Expose
private int userId;
@SerializedName("full_name")
@Expose
private String fullName;
@SerializedName("email_address")
@Expose
private String emailAddress;
@SerializedName("end_date")
@Expose
private Object endDate;
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public String getFullName() {
return fullName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
public String getEmailAddress() {
return emailAddress;
}
public void setEmailAddress(String emailAddress) {
this.emailAddress = emailAddress;
}
public Object getEndDate() {
return endDate;
}
public void setEndDate(Object endDate) {
this.endDate = endDate;
}
}
相反
Call<Response> auth = .// setup
auth.enqueue(new Callback<Response>() {
@Override
public void onResponse(Call<Response> call, Response<Response> response) {
if (response.isSuccessful() ) {
Response respojo = response.body();
if(respojo.getStatus().equals("success"){
Log.i("User: ","" + respojo.getUser().getFullname());
}else {
Log.i("Error: ","" + respojo.getReason());
}
}
} else {
response.errorBody();
}
}
@Override
public void onFailure(Call<Response> call, Throwable t) {
t.printStackTrace();
}
});
答案 2 :(得分:1)
在进行2.0改造时,最好的方法是使用Gson转换器。只需使用可选的json键添加@Nullable
注解(在您的情况下为用户和原因),这样它在解析时不会崩溃或不会生成nullpointer异常。因此,您的模型类如下所示。
public class YourModelClass {
@SerializedName("status")
@Expose
public String status;
@Nullable
@SerializedName("user")
@Expose
public User user;
@Nullable
@SerializedName("reason")
@Expose
public String reason;
public class User {
@SerializedName("user_id")
@Expose
public Integer userId;
@SerializedName("full_name")
@Expose
public String fullName;
@SerializedName("email_address")
@Expose
public String emailAddress;
@SerializedName("end_date")
@Expose
public Object endDate;
}
}
在您要请求解析的活动或片段中,如下所示
@Override
public void onResponse(Call<YourModelClass> call, Response<YourModelClass> response) {
if(response.body.yourModelClass.status.equals("succ")) {
User changesList = response.body().user;
//perform action with user data
} else {
Log.d("failer", response.body().reason)
}
}
@Override
public void onFailure(Call<YourModelClass> call, Throwable t) {
t.printStackTrace();
}
希望它对您有用。 使用android studio插件DTO Genrater创建pojo。
答案 3 :(得分:0)
您可以为此创建一个融合类,例如:
public class Foo {
String status;
String reason;
UserModel user;
// Constructors, getter/setter, others
// ...
}
然后调用Retrofit like
Call<Foo> callToYourAPI();
以及要拥有用户的时间:
if (foo.reason == "success") // or if (foo.user != null)
// do something with foo.user
在这种情况下,转换会自动完成。如果您的问题是字段可以是一种或另一种,那么您将需要一个转换器。