问题描述
RetrofitClient.APIError错误= RetrofitClient .ErrorUtils.parseError(response,retrofit);
错误为空。更多详细信息:
这是API返回错误的格式:
message:凭证不正确,
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();
$ b这是我的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 void void addHeadersRequiredForAllRequests(OkHttpClient httpClient,final String appVersion){
$ b $ class RequestInterceptor实现拦截器{
@Override
public com.squareup.okhttp.Response拦截(链式链接)抛出IOException {
请求请求= 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]);
API错误错误;
尝试{
error = converter.convert(response.errorBody());
} catch(IOException e){
e.printStackTrace();
返回新的APIError();
} catch(Exception e){
e.printStackTrace();
返回新的APIError();
}
返回错误;
public static class APIError {
@SerializedName(error)
public
ErrorResponse loginError;
$ b $ 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;
$ b @Override
public String toString(){
returnLoginErrorResponseBody {+
message ='+ getMessage()+' \''+
,statusCode =+ statusCode +
'}';
}
public void setMessage(String message){
this.message = message;
}
}
}
}
我得到了本教程中的错误utils类,但是稍微改变了它,因为它们的示例中的错误格式不同:
编辑:这是 Converter class:
/ **
*转换对象作为HTTP主体的对象。用
注册转换器*使用{@link Retrofit.Builder#addConverterFactory(Factory)}进行改造。
* /
public interface Converter< F,T> {
转换(F值)抛出IOException;
抽象类工厂{
/ **
*创建用于将HTTP响应主体转换为{@code type}的{@link Converter},或者如果它为$ b $,则为null b *不能由该工厂处理。
* /
公共转换器< ResponseBody,?> fromResponseBody(Type type,Annotation [] annotations){
return null;
}
/ **
*创建用于将{code类型}转换为HTTP请求主体的{@link Converter},如果
*不能为null由该工厂处理。
* /
公共转换器<?,RequestBody> toRequestBody(类型类型,注解[]注释){
返回null;
解决方案您可以参考以下内容:
自定义类:
public class ResponseError {
错误错误;
class错误{
int statusCode;
字符串消息;
$ b将以下内容添加到 WebAPIService 界面:
@GET(/ api / geterror)
调用< ResponseError> ; getError2();
然后,在 MainActivity.java中:
调用< 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());
}
}
$ b @Override
public void onFailure(Throwable t){
Log.e(LOG_TAG,t.toString());
}
});
我刚刚测试过您的 RetrofitClient 类与我的Web服务。我给你的 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)
调用< JSONObject> getError();
}
MainActivity:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(API_URL_BASE)
.addConverterFactory(GsonConverterFactory.create() )
.build();
WebAPIService服务= retrofit.create(WebAPIService.class);
调用< JSONObject> jsonObjectCall = service.getError();
jsonObjectCall.enqueue(new Callback< JSONObject>(){
@Override $ b $ public void onResponse(Response< JSONObject> 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());
}
}
$ b @Override
public void onFailure(Throwable t){
Log.e(LOG_TAG,t.toString());
}
});
我的网路服务(Asp.Net Web API):
根据您的JSON响应数据,我使用了以下代码:
[Route(api / geterror )]
public HttpResponseMessage GetError()
{
var detailError = new
{
message =凭证不正确,
statusCode = 401
};
var myError = new
{
error = detailError
};
返回Request.CreateResponse(HttpStatusCode.Unauthorized,myError);
}
工作正常!希望它有帮助!
I am using Retrofit 2 and I am getting a null pointer exception at this line:
RetrofitClient.APIError error = RetrofitClient.ErrorUtils.parseError(response, retrofit);The error is null. More details:
This is the format that the API returns the error in:
{ "error": { "message": "Incorrect credentials", "statusCode": 401 } }Here is my login Callback code:
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(""); } } }This is my Retrofit 2 class:
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; } } } }I got the error utils class from this tutorial, but changed it slightly because the error formatting in their example is different:
EDIT: This is the Converter class:
/** * 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; } } }解决方案UPDATE:
If you want to use a custom class instead of JSONObject below, you can refer to the following:
Custom class:
public class ResponseError { Error error; class Error { int statusCode; String message; } }Add the following to WebAPIService interface:
@GET("/api/geterror") Call<ResponseError> getError2();Then, inside 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()); } });I have just tested your RetrofitClient class with my web service. I made a small update to your APIError class as the following (add 2 constructors, actually they are not called):
public APIError(){ this.loginError = new ErrorResponse(); } public APIError(int statusCode, String message) { this.loginError = new ErrorResponse(); this.loginError.statusCode = statusCode; this.loginError.message = message; }Interface:
public interface WebAPIService { @GET("/api/geterror") Call<JSONObject> getError(); }MainActivity:
// 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, 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()); } });My web service (Asp.Net Web API):
According to your JSON response data, I have used the following code:
[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); }It's working! Hope it helps!
这篇关于在改造2中无法解析错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!