Converting JSON response to POJO with Retrofit usi

2019-02-24 23:24发布

问题:

I have to work with an API which using JSend format.

Long story short it is using HTTP status codes which indicates status like:

  • 200 is Success
  • 406 is Unauthorized

Which is good because I can determine from this whether my API request is succeed or not.

BUT:

As JSend format has it's own thing, it has ALSO have a little status indicator at response just like this:

{
    status : "success",
    data : { "post" : { "id" : 2, "title" : "Another blog post", "body" : "More content" }}
}

So it has a 'status' field which ALSO shows whether the API request is succeed or not.

PROBLEM:

Retrofit made to parse the response to POJO so it assumes that the responses contains ONLY the Model and no indicators for success, just like this for example: (A post Model instance)

{ "id" : 2, "title" : "Another blog post", "body" : "More content" }

My question is:

Is there a solution for this? Can I pre-parse the status indicators, split the 'data' (Model) part of the response and give it to retrofit for parse only that part?

If not I would have to add a "status" attribute to each of my models which is clearly not a walkable way, I won't do that.

Should I just stick with manual parsing and use ResponseBody instead of my Models at

void onResponse(Call<T> call, Response<T> response); for T type paramter?

Because in that way I can use .string() and convert the string to JSON and after that I can parse my Models manually like writing the parser for them.

I would really like to use Retrofit's feature for automatic parsing because with JSend I just cannot imagine how could be this properly done if anyhow at all.

I cannot change the API it's going to be this way.

回答1:

Here is my Response class.

public class Response<T> implements Serializable {
private T data;
private String status;

public T getData() {
    return data;
}

public void setData(T data) {
    this.data = data;
}

public String getStatus() {
    return status;
}

public void setStatus(String status) {
    this.status = status;
}

}

Here is my api call.

Callback<com.shippn.api.models.Response<T>> callback = new Callback<com.shippn.api.models.Response<T>>() {
        @Override
        public void onResponse(Call<com.shippn.api.models.Response<T>> call, Response<com.shippn.api.models.Response<T>> response) {
            checkStatus(response.body());
        }

        @Override
        public void onFailure(Call<com.shippn.api.models.Response<T>> call, Throwable t) {
            fail();
        }
    };
    call.enqueue(callback);

T parameter is type of your data from api. I mean if you want to get data in Post type put Post insted of T. If you want to get ArrayList<Post> put ArrayList<Post>.

If data field is empty or null in your api response, Response.data will be null or empty, it wont throw an exception.

When you get response from api, first check Response.status if it is "success" or not. If it is "success" get data from Response, if it is not take your error actions.



回答2:

One possible way is to create a wrapper for your models like

public class Example<T> {
    String status;
    T data;

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}


回答3:

What you can do is you can have the status of the post request without using this. The problem is that the parameter names are not string and will not be parsed in POJO.But you can get the status of you request like this.

@Override
            public void onResponse(Call<Object> call, retrofit2.Response<Object> response) {
                alertDialog.dismiss();
                if (response.isSuccessful() && response.body() != null) {
                    //if the response is received here it means it was success
                }else if(response.errorBody()!=null){
                    //if the response is received here it means it was error
                }
            }

            @Override
            public void onFailure(Call<Object> call, Throwable t) {
                //if the response is received here it means it was failure
                t.printStackTrace();
            }
        });

EDIT In this way you can have the status with using pojo and you can parse the error simply as in this link

EDIT 1 Moreover for getting the proper error code you can extend your callback class to a class like

public class ErrorValues {
    public int code=0;
    public String error;
}

Then if the request was completed with a error.Inside

else if(response.errorBody()!=null){
 int error=response.body.code == 404 ....
                    }

Like this you can check which error code was thrown by the request.