当前位置:  开发笔记 > 后端 > 正文

无法在Retrofit 2中解析错误

如何解决《无法在Retrofit2中解析错误》经验,为你挑选了1个好方法。

我正在使用Retrofit 2,我在这一行得到一个空指针异常:

 RetrofitClient.APIError error = RetrofitClient.ErrorUtils.parseError(response, retrofit);

错误为空.更多细节:

这是API返回错误的格式:

{
  "error": {
    "message": "Incorrect credentials",
    "statusCode": 401
  }
}

这是我的登录回调代码:

new Callback() {

    @Override
    public void onResponse(Response response, Retrofit retrofit) {
       if (listener != null) {
           if (response.isSuccess() && response.body() != null) {

               User user = RetrofitUserToUserMapper.fromRetrofitUser(response.body().getLoginUser());

           } else {

               RetrofitClient.APIError error = RetrofitClient.ErrorUtils.parseError(response, retrofit);
               listener.onUserLoginFailure(error.getErrorMessage()); // NPE - error is null
           }
        }
    }

    @Override
    public void onFailure(Throwable t) {

        if (listener != null) {
            listener.onUserLoginFailure("");
        }
    }
}

这是我的Retrofit 2课程:

public class RetrofitClient {

    public static final String API_ROOT = "http://example.com/api/v1/";
    private static final String HEADER_OS_VERSION = "X-OS-Type";
    private static final String HEADER_APP_VERSION = "X-App-Version";
    private static final String HEADER_OS_VERSION_VALUE_ANDROID = "android";


    private RetrofitClient() {
    }

    private static Retrofit INSTANCE;

    public static Retrofit getInstance() {
        if (INSTANCE == null) {
            setupRestClient();
        }
        return INSTANCE;
    }

    public static void setupRestClient() {

        OkHttpClient httpClient = new OkHttpClient();
        addHeadersRequiredForAllRequests(httpClient, BuildConfig.VERSION_NAME);

        INSTANCE = new Retrofit.Builder()
                .baseUrl(API_ROOT)
                .addConverterFactory(GsonConverterFactory.create())
                .client(httpClient)
                .build();
    }

    private static void addHeadersRequiredForAllRequests(OkHttpClient httpClient, final String appVersion) {

        class RequestInterceptor implements Interceptor {

            @Override
            public com.squareup.okhttp.Response intercept(Chain chain) throws IOException {
                Request request = chain.request().newBuilder()
                        .addHeader(HEADER_OS_VERSION, HEADER_OS_VERSION_VALUE_ANDROID)
                        .addHeader(HEADER_APP_VERSION, appVersion)
                        .build();
                return chain.proceed(request);
            }
        }

        httpClient.networkInterceptors().add(new RequestInterceptor());
    }

    public static class ErrorUtils {

        public static APIError parseError(Response response, Retrofit retrofit) {
            Converter converter =
                    retrofit.responseConverter(APIError.class, new Annotation[0]);

            APIError error;

            try {
                error = converter.convert(response.errorBody());
            } catch (IOException e) {
                e.printStackTrace();
                return new APIError();
            } catch (Exception e) {
                e.printStackTrace();
                return new APIError();
            }

            return error;
        }
    }

    public static class APIError {
        @SerializedName("error")
        public
        ErrorResponse loginError;

        public ErrorResponse getLoginError() {
            return loginError;
        }

        public String getErrorMessage() {
            return loginError.message;
        }

        private class ErrorResponse {
            @SerializedName("message")
            private String message;
            @SerializedName("statusCode")
            public int statusCode;

            public String getMessage() {
                return message;
            }

            public int getStatusCode() {
                return statusCode;
            }

            @Override
            public String toString() {
                return "LoginErrorResponseBody{" +
                        "message='" + getMessage() + '\'' +
                        ", statusCode=" + statusCode +
                        '}';
            }

            public void setMessage(String message) {
                this.message = message;
            }
        }
    }


}

我从本教程获得了错误utils类,但稍微改了一下因为它们的示例中的错误格式不同:

编辑:这是Converter班级:

/**
 * Convert objects to and from their representation as HTTP bodies. Register a converter with
 * Retrofit using {@link Retrofit.Builder#addConverterFactory(Factory)}.
 */
public interface Converter {
  T convert(F value) throws IOException;

  abstract class Factory {
    /**
     * Create a {@link Converter} for converting an HTTP response body to {@code type} or null if it
     * cannot be handled by this factory.
     */
    public Converter fromResponseBody(Type type, Annotation[] annotations) {
      return null;
    }

    /**
     * Create a {@link Converter} for converting {@code type} to an HTTP request body or null if it
     * cannot be handled by this factory.
     */
    public Converter toRequestBody(Type type, Annotation[] annotations) {
      return null;
    }
  }
}

BNK.. 6

更新:

如果要使用自定义类而不是JSONObject下面的类,可以参考以下内容:

自定义类:

public class ResponseError {

    Error error;

    class Error {
        int statusCode;
        String message;
    }
}

将以下内容添加到WebAPIService界面:

@GET("/api/geterror")
Call getError2();

然后,里面MainActivity.java:

Call responseErrorCall = service.getError2();
responseErrorCall.enqueue(new Callback() {
    @Override
    public void onResponse(Response response, Retrofit retrofit) {
        if (response.isSuccess() && response.body() != null){
            Log.i(LOG_TAG, response.body().toString());
        } else {
            if (response.errorBody() != null){
                RetrofitClient.APIError error = RetrofitClient.ErrorUtils.parseError(response, retrofit);
                Log.e(LOG_TAG, error.getErrorMessage());
            }
        }
    }

    @Override
    public void onFailure(Throwable t) {
        Log.e(LOG_TAG, t.toString());
    }
});

我刚RetrofitClient用我的网络服务测试了你的课程.我对你的APIError类做了一个小的更新,如下所示(添加2个构造函数,实际上它们没有被调用):

public APIError(){
    this.loginError = new ErrorResponse();
}

public APIError(int statusCode, String message) {
    this.loginError = new ErrorResponse();
    this.loginError.statusCode = statusCode;
    this.loginError.message = message;
}

接口:

public interface WebAPIService {
    @GET("/api/geterror")
    Call getError();
}

主要活动:

// Retrofit 2.0-beta2
Retrofit retrofit = new Retrofit.Builder()
        .baseUrl(API_URL_BASE)
        .addConverterFactory(GsonConverterFactory.create())
        .build();

WebAPIService service = retrofit.create(WebAPIService.class);

Call jsonObjectCall = service.getError();
jsonObjectCall.enqueue(new Callback() {
    @Override
    public void onResponse(Response response, Retrofit retrofit) {
        if (response.isSuccess() && response.body() != null){
            Log.i(LOG_TAG, response.body().toString());
        } else {
            if (response.errorBody() != null){
                RetrofitClient.APIError error = RetrofitClient.ErrorUtils.parseError(response, retrofit);
                Log.e(LOG_TAG, error.getErrorMessage());
            }
        }
    }

    @Override
    public void onFailure(Throwable t) {
        Log.e(LOG_TAG, t.toString());
    }
});

我的Web服务(Asp.Net Web API):

根据您的JSON响应数据,我使用了以下代码:

[Route("api/geterror")]
public HttpResponseMessage GetError()
{
    var detailError = new
    {
        message = "Incorrect credentials",
        statusCode = 401
    };

    var myError = new
    {
        error = detailError
    };            

    return Request.CreateResponse(HttpStatusCode.Unauthorized, myError);
}

它的工作原理!希望能帮助到你!



1> BNK..:

更新:

如果要使用自定义类而不是JSONObject下面的类,可以参考以下内容:

自定义类:

public class ResponseError {

    Error error;

    class Error {
        int statusCode;
        String message;
    }
}

将以下内容添加到WebAPIService界面:

@GET("/api/geterror")
Call getError2();

然后,里面MainActivity.java:

Call responseErrorCall = service.getError2();
responseErrorCall.enqueue(new Callback() {
    @Override
    public void onResponse(Response response, Retrofit retrofit) {
        if (response.isSuccess() && response.body() != null){
            Log.i(LOG_TAG, response.body().toString());
        } else {
            if (response.errorBody() != null){
                RetrofitClient.APIError error = RetrofitClient.ErrorUtils.parseError(response, retrofit);
                Log.e(LOG_TAG, error.getErrorMessage());
            }
        }
    }

    @Override
    public void onFailure(Throwable t) {
        Log.e(LOG_TAG, t.toString());
    }
});

我刚RetrofitClient用我的网络服务测试了你的课程.我对你的APIError类做了一个小的更新,如下所示(添加2个构造函数,实际上它们没有被调用):

public APIError(){
    this.loginError = new ErrorResponse();
}

public APIError(int statusCode, String message) {
    this.loginError = new ErrorResponse();
    this.loginError.statusCode = statusCode;
    this.loginError.message = message;
}

接口:

public interface WebAPIService {
    @GET("/api/geterror")
    Call getError();
}

主要活动:

// Retrofit 2.0-beta2
Retrofit retrofit = new Retrofit.Builder()
        .baseUrl(API_URL_BASE)
        .addConverterFactory(GsonConverterFactory.create())
        .build();

WebAPIService service = retrofit.create(WebAPIService.class);

Call jsonObjectCall = service.getError();
jsonObjectCall.enqueue(new Callback() {
    @Override
    public void onResponse(Response response, Retrofit retrofit) {
        if (response.isSuccess() && response.body() != null){
            Log.i(LOG_TAG, response.body().toString());
        } else {
            if (response.errorBody() != null){
                RetrofitClient.APIError error = RetrofitClient.ErrorUtils.parseError(response, retrofit);
                Log.e(LOG_TAG, error.getErrorMessage());
            }
        }
    }

    @Override
    public void onFailure(Throwable t) {
        Log.e(LOG_TAG, t.toString());
    }
});

我的Web服务(Asp.Net Web API):

根据您的JSON响应数据,我使用了以下代码:

[Route("api/geterror")]
public HttpResponseMessage GetError()
{
    var detailError = new
    {
        message = "Incorrect credentials",
        statusCode = 401
    };

    var myError = new
    {
        error = detailError
    };            

    return Request.CreateResponse(HttpStatusCode.Unauthorized, myError);
}

它的工作原理!希望能帮助到你!

推荐阅读
跟我搞对象吧
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有