改造:Json解析器根据响应

时间:2018-09-25 16:31:42

标签: java android json rest retrofit

我有一个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'

如果唯一的解决方案是自定义转换器,请清楚地解释一下,因为我在这个主题上真的很陌生。

4 个答案:

答案 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

在这种情况下,转换会自动完成。如果您的问题是字段可以是一种或另一种,那么您将需要一个转换器。