I am writing an application that uses RoboSpice. In the request listener onRequestFailure( SpiceException arg0 ) is there a way to know for sure that the error was a result of a
With google http client for java you can also intercept error responses like so:
public static class InitIntercept implements
HttpRequestInitializer, HttpUnsuccessfulResponseHandler {
@Override
public boolean handleResponse(
HttpRequest request,
HttpResponse response,
boolean retrySupported) throws IOException {
if (response.getStatusCode() == HttpStatusCodes.STATUS_CODE_UNAUTHORIZED) {
...
}
return false;
}
@Override
public void initialize(HttpRequest request) throws IOException {
request.setUnsuccessfulResponseHandler(this);
}
}
and in your GoogleHttpClientSpiceService:
@Override
public HttpRequestFactory createRequestFactory() {
return AndroidHttp
.newCompatibleTransport().createRequestFactory(new InitIntercept());
}
I looked over Spring-Android closer and it seems getRestTemplate().getForObject(...) throws a HttpClientErrorException when a 401 or any network error occurs.
Looking at the Robo Spice for where they catch that exception I found they catch it in RequestProcessor.java in the processRequest function. They pass the Spring-Android exception in as the throwable inside their SpiceException that inherits from Java exception class.
So you just do the following inside your RoboSpice RequestListener to see if it a 401 UNAUTHORIZED exception.
private class MyRequestListener implements RequestListener<RESULT> {
public void onRequestFailure( SpiceException arg0 ) {
if(arg0.getCause() instanceof HttpClientErrorException)
{
HttpClientErrorException exception = (HttpClientErrorException)arg0.getCause();
if(exception.getStatusCode().equals(HttpStatus.UNAUTHORIZED))
{
Ln.d("401 ERROR");
}
else
{
Ln.d("Other Network exception");
}
}
else if(arg0 instanceof RequestCancelledException)
{
Ln.d("Cancelled");
}
else
{
Ln.d("Other exception");
}
};
public void onRequestSuccess( RESULT result ) {
Ln.d("Successful request");
}
}
I am using the google http client with RoboSpice and has the same issue but was easy to solve with request.setThrowExceptionOnExecuteError(false);
and checking the response code on the resulting HttpResponse
object
EDIT: the code snippit as requested
HttpRequest request = getHttpRequestFactory().buildPostRequest(new GenericUrl(URL), content);
request.setThrowExceptionOnExecuteError(false);
HttpResponse response = request.execute();
switch(response.getStatusCode())
{
case HttpStatusCodes.STATUS_CODE_UNAUTHORIZED:
return new MyBaseResponse(responseBody);
default:
throw new RuntimeException("not implemented yet");
}
For those who can't resolve HttpClientErrorException
into a type, and cannot find any documentations online, (that's me), here is my approach:
In my fragment, here is my listener:
private final class MyRequestListener extends RequestListener<MyResponse> {
@Override
public void onRequestFailure(SpiceException spiceException) {
super.onRequestFailure(spiceException);
if (spiceException instanceof NetworkException) {
NetworkException exception = (NetworkException) spiceException;
if (exception.getCause() instance RetrofitError) {
RetrofitError error = (RetrofitError) exception.getCause();
int httpErrorCode = error.getResponse().getStatus();
// handle the error properly...
return;
}
}
// show generic error message
}
}
Hope this maybe helpful to someone.
I would move the whole if
clause into a static function so it can be reused. Just return 0 if exception doesn't match. And I haven't verify if any of the casting can be removed...
It's even easier than all of the other answers.
For me @Scrotos answer was problematic, because the whole point for the 401 to be caught is to make the request to auth endpoint and then make the primary request again. So that you only return to UI with desired data or some "real" error.
So it shouldn't be done inside the callback, but rather inside loadDataFromNetwork()
itself.
I've done it this way:
@Override
public SubscriptionsContainer loadDataFromNetwork() {
//...
ResponseEntity<SubscriptionsContainer> response = null;
try {
response = getRestTemplate().exchange(
//your request data
);
} catch (HttpClientErrorException e) {
HttpStatus statusCode = e.getStatusCode();
//check the exception, if it's 401, make call to auth and repeat loadDataFromNetwork()
}