我正在使用Retrofit 2,我在这一行得到一个空指针异常:
RetrofitClient.APIError error = RetrofitClient.ErrorUtils.parseError(response,retrofit);
错误为空.更多细节:
这是API返回错误的格式:
{ "error": { "message": "Incorrect credentials","statusCode": 401 } }
new Callback<LoginResponse>() { @Override public void onResponse(Response<LoginResponse> 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<ResponseBody,APIError> 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<F,T> { 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<ResponseBody,?> 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<?,RequestBody> toRequestBody(Type type,Annotation[] annotations) { return null; } } }
解决方法
更新:
如果要在下面使用自定义类而不是JSONObject,可以参考以下内容:
自定义类:
public class ResponseError { Error error; class Error { int statusCode; String message; } }
@GET("/api/geterror") Call<ResponseError> getError2();
然后,在MainActivity.java中:
Call<ResponseError> responseErrorCall = service.getError2(); responseErrorCall.enqueue(new Callback<ResponseError>() { @Override public void onResponse(Response<ResponseError> 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服务测试了你的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<JSONObject> 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<JSONObject> jsonObjectCall = service.getError(); jsonObjectCall.enqueue(new Callback<JSONObject>() { @Override public void onResponse(Response<JSONObject> response,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); }
它的工作原理!希望能帮助到你!