johnny68
johnny68

Reputation: 431

Retrofit2 NULL response in onResponse even when Data is not NULL

So, my problem is fairly straightforward.

This is the response I am getting through the API call.

D/OkHttp: {"status":"error","status_code":"500","error_msg":"There was an error trying to send the password reset email."}
<-- END HTTP (220-byte body)

This is my code to handle the calls

 Call<PasswordReset> forgotPasswordCall = apiInterface.Reset(email);
    forgotPasswordCall.enqueue(new Callback<PasswordReset>() {
        @Override
        public void onResponse(Call<PasswordReset> call, Response<PasswordReset> response) {
            PasswordReset passwordReset = response.body();
            try {
                if (passwordReset.getStatusCode() != null && passwordReset.getStatusCode().equals("200")) {   //line 133
                    Log.d("Success", "Password Reset Email Sent");
                    new CustomToast().showToast(getContext(), view, "Password Email sent");
                    new LoginActivity().replaceFragment("left");
                } else {
                    String test = passwordReset.getStatusCode();
                    Log.d("Failure", test);
                    hideDialog();
                }
            }
            catch (Exception e){
                e.printStackTrace();
                hideDialog();
            }
        }

        @Override
        public void onFailure(Call<PasswordReset> call, Throwable t) {
            Log.d("Failure", "Password Reset Email Not Sent");
            new CustomToast().showToast(getContext(), view, "Email Not Sent");
            new LoginActivity().replaceFragment("left");
            hideDialog();
        }
    });

And this is the exception I am catching

W/System.err: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String in.siddhant.anetpays_customer.POJO.PasswordReset.getStatusCode()' on a null object reference
    at in.siddhant.anetpays_customer.Login.Fragments.ForgotPassword$1.onResponse(ForgotPassword.java:133)

How can my response be null if I am getting some data ?

PasswordReset.class

    public class PasswordReset {


    @SerializedName("data")
    private String data;
    @SerializedName("status_code")
    private String statusCode;
    @SerializedName("status")
    private String status;

    public String getData() {
        return data;
    }

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

    public String getStatusCode() {
        return statusCode;
    }

    public void setStatusCode(String statusCode) {
        this.statusCode = statusCode;
    }

    public String getStatus() {
        return status;
    }

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

Retrofit Client

public static Retrofit getClient() {

        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();


        retrofit = new Retrofit.Builder()
                .baseUrl("http://xsdf/")
                .addConverterFactory(GsonConverterFactory.create())
                .client(client)
                .build();



        return retrofit;

API_Interface

@FormUrlEncoded
    @POST("/ddd/pwdresetrequest")
    Call<PasswordReset>Reset(@Field("email")String email);

P.S - The API itself has some problem and always returns "status":"error" but this shouldn't affect the application, right ? Also I am happy to share more code. Thanks in advance.

Solution I am posting the solution as suggested as per the accepted answer, Hope it helps someone who comes looking.

forgotPasswordCall.enqueue(new Callback<PasswordReset>() {
            @Override
            public void onResponse(Call<PasswordReset> call, Response<PasswordReset> response) {
                     if (!response.isSuccessful()){
                        Gson gson = new Gson();
                        PasswordReset passwordReset1 = gson.fromJson(response.errorBody().charStream(), PasswordReset.class);
                        if (passwordReset1.getStatusCode().equals("500")){
                            new CustomToast().showToast(getContext(), view, "Password Email not sent");
                            hideDialog();
                        }
                        else {
                            Thread.dumpStack();
                            hideDialog();
                        }

                    }
                     else if (response.isSuccessful()) {
                         Log.d("Success", "Password Reset Email Sent");
                         new CustomToast().showToast(getContext(), view, "Password Email sent");
                         new LoginActivity().replaceFragment("left");
                     }

As for the theory, onResponse method of retrofit2 is called when we get some response and onFailure is called when the process of establishing and receiving a response is not met. I had overlooked this simple fact. So, if someone does come looking and reading still, I will suggest you to also check your response.body() if its successful or not. Happy Coding!

Upvotes: 1

Views: 818

Answers (1)

Fred
Fred

Reputation: 17085

From the retrofit's javadoc for Response you can read that body() returns the deserialized response from a successful response. Unfortunately, seems like you have an unsuccessful response, given that you seem to receive a 500.

errorBody() is what you want to use. However, this returns the raw response, so you'll have to deserialize it yourself.

There's a lot of ways you can do this. One might be using gson to deserialize the body:

new Gson().fromJson(response.errorBody().body().string(), YourModel.class);

PS: Just because you end up on onResponse it doesn't mean you have a successful response. However, from your code it seems you already know this and are checking for the http status 200.

Upvotes: 1

Related Questions