I'm trying to test retrofit with robolectric. But I always get an IndexOutOfBoundsException when I call Robolectric.getSentHttpRequest(0). Can anyone help me?
here is my code:
#Before
public void setup() {
Robolectric.setDefaultHttpResponse(200, "OK");
commonRequest = RequestFactory.getRestAdapter().create(CommonRequest.class);
}
#Test
public void testGet_shouldApplyCorrectHeaders() throws Exception {
commonRequest.register("Token", "{}", null);
HttpRequest sentHttpRequest = Robolectric.getSentHttpRequest(0);
assertThat(sentHttpRequest.getHeaders("Authorization")[0].getValue(), equalTo("Token"));
}
Thank you very much.
It seems that you're missing the send request part. That's why you keep getting IndexOutOfBoundsException. You should send the request first take a look in the first example (testGet_FormsCorrectRequest_noBasicAuth) here
Related
I want to send a String message to database when user presses a specific button in the LibGDX game I am designing for android. How do I go about doing that? Following is the code I tried. But it does not work.
Net.HttpRequest httpRequest = new Net.HttpRequest();
httpRequest.setMethod("POST");
httpRequest.setUrl("URL is here");
httpRequest.setContent("INSERT INTO `game_table` (`Button`) VALUES ('Button 1 Pressed')");
Net.HttpResponseListener httpResponseListener = new Net.HttpResponseListener() {
#Override
public void handleHttpResponse(Net.HttpResponse httpResponse) {
Gdx.app.log("Log httpResponse", httpResponse.getResultAsString());
}
#Override
public void failed(Throwable t) {
}
#Override
public void cancelled() {
}
};
Gdx.net.sendHttpRequest(httpRequest,httpResponseListener);
Log does not provide anything in android monitor. I also tried using AsyncTask and without AsyncTask to implement this code. But neither works.
Am I missing something? If so could you give me small code snippet that will work?
You don't need to use an AsyncTask, libGDX' HTTPRequest is async out of the box.
You did not log anything if the request fails or is cancelled so probably that's the case.
I have integrated Hola CDN in my android app & when I am trying to attach my ExoPlayer after connection established with Hola CDN by doing this-
if(api.is_connected())
api.attach(player.get_player(), userAgent, new TransferListener() {
#Override
public void onTransferStart() {
System.out.print("start");
}
#Override
public void onBytesTransferred(int i) {
System.out.print("start byte");
}
#Override
public void onTransferEnd() {
System.out.print("start end");
}
}, videoUrl);
,It gives this error -
java.lang.IllegalArgumentException at
com.google.android.exoplayer.util.Assertions.checkNotEmpty(Assertions.java:122)
As per my understanding & references. Getting java.lang.IllegalArgumentException means passing undesired param. In your case, Assertions.checkNotEmpty()method needs NON EMPTY String. But, getting NULL String due to something [that you need to trace out] & that's the reason your are getting above exception.
Giving you the below description,
checkNotEmpty(String string) Throws IllegalArgumentException if string
is null or zero length.
on
1]https://google.github.io/ExoPlayer/doc/reference/com/google/android/exoplayer2/util/Assertions.html
2]https://google.github.io/ExoPlayer/doc/reference/com/google/android/exoplayer2/util/Assertions.html#checkNotEmpty-java.lang.String-
If you fix this then rest of the things might work as you expect.
I have a custom error handler that checks RetrofitError it gets passed and rethrows it as custom exceptions
private static ErrorHandler getErrorHandler() {
return new ErrorHandler() {
#Override
public Throwable handleError(RetrofitError cause) {
switch (cause.getKind()) {
case NETWORK: return new NetworkException(cause);
case HTTP: return new ApiException(cause);
default: return cause;
}
}
};
}
If this is my endpoint
#GET(USERS_GET_URL)
User getUsers() throws NetworkException, ApiException;
while executing synchronous request I try...catch and handle each custom exception as I want. When it is done asynchronously using
#GET(USERS_GET_URL)
void getUsers(Callback<User> cb) throws NetworkException, ApiException;
the handled exception gets rethrown as RetrofitError. The following snippet of code is from CallbackRunnable class of Retrofit which executes the request
try {
final ResponseWrapper wrapper = obtainResponse();
callbackExecutor.execute(new Runnable() {
#Override public void run() {
callback.success((T) wrapper.responseBody, wrapper.response);
}
});
} catch (RetrofitError e) {
Throwable cause = errorHandler.handleError(e);
final RetrofitError handled = cause == e ? e : unexpectedError(e.getUrl(), cause);
callbackExecutor.execute(new Runnable() {
#Override public void run() {
callback.failure(handled);
}
});
}
As it can be seen, my custom exceptions are getting rethrown as RetrofitError which makes me loose valuable information. Is there any way I can bypass custom error handling for just the async requests?
In your ErrorHandler you pathing original RetrofitError as cause, so as result in your Callback#failure(RetrofitError error) to get actual information you need to write next code: error.getCause().getCause(). This error will contain response that server send with all the data.
But error handler was created for sync request and after some time square team decided to close this gap this way. For more info you can read: https://gist.github.com/benvium/66bf24e0de80d609dac0
As for me, I don't recommend to use ErrorHander for async way, because I don't find any good solution to handle different types of error. It was much easier to get data right from initial RetrofitError.
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 401 HTTP Error occurred?
I have a back end service, that returns a 401 error when a token expires, when that occurs I need to prompt the user to re-enter their credentials.
Is there anyway to know that a 401 HTTP error specifically occurred?
Below is an example of my request.
public class LookupRequest extends SpringAndroidSpiceRequest <Product> {
public String searchText;
public String searchMode;
public LookupRequest() {
super( Product.class );
}
#Override
public Product loadDataFromNetwork() throws Exception {
String url = String.format("%s/Lookup?s=%s&m=%s", Constants.BASE_URL, searchText, searchMode);
Ln.d("Calling URL: %s", url);
return getRestTemplate().getForObject(url, Product.class );
}
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...
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());
}
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()
}
Hi I'm trying to add events to a calender with the google-api-java-client and calender API service for a android app. I used the calendersample project created by Yaniv Inbar as a template which works great. When inserting 1 event to the selected calender works perfectly but when i try to batch add events to the calendar get an Illegal state exception.
in the example you could batch add calenders like this.
whole class can be found here AsyncBatchInsertCalendars.java
#Override
protected void doInBackground() throws IOException {
BatchRequest batch = client.batch();
for (Calendar calendar : calendars) {
client.calendars().insert(calendar).setFields(CalendarInfo.FIELDS)
.queue(batch, new JsonBatchCallback<Calendar>() {
public void onSuccess(Calendar calendar, GoogleHeaders headers) {
model.add(calendar);
}
#Override
public void onFailure(GoogleJsonError err, GoogleHeaders headers)
throws IOException {
Utils.logAndShowError(activity, CalendarSampleActivity.TAG, err.getMessage());
}
});
}
batch.execute();
}
I rewrote the class so that it would be events instead of calenders. if you look at the whole class AsyncBatchInsertEvent.java you'll see that in the doInBackground methode I also loop through a arraylist creating a list of events. which should than be added to the batch to be inserted on the given calendar.
#Override
protected void doInBackground() throws IOException {
BatchRequest batch = client.batch();
for (Event event : events) {
client.events().insert(calender.id, event).queue(batch,
new JsonBatchCallback<Event>() {
public void onSuccess(Event event, GoogleHeaders headers) {
//TODO show succes message.
}
#Override
public void onFailure(GoogleJsonError err, GoogleHeaders headers)
throws IOException {
Utils.logAndShowError(activity, EventActivity.TAG, err.getMessage());
}
});
}
batch.execute();
}
If I use this then get a an exception and the app crashes
W/dalvikvm(21030): threadid=20: thread exiting with
uncaught exception (group=0x40c19930)
E/AndroidRuntime(21030): FATAL EXCEPTION: AsyncTask #2
E/AndroidRuntime(21030): java.lang.RuntimeException: An error occured
while executing doInBackground()
The full stacktrace of the error can be found here at pastebin log.txt. Does anyone know how to fix this or did I implement the code incorrectly? the whole code can be found here at pastbin AsyncBatchInsertEvent.java
Stupid me, the arraylist events was empty cause i checked a string == string instead of string.equels(string).