LoginResponse and LoginRequest are my model class. and i display error
Response class is from retrofit library and really cant solve this. Rxjava flatmap Func1 to retrofit.Response class.
public Observable<LoginResponse> performLogin(String emailId, String password) {
LoginRequest requestBody = new LoginRequest(emailId,password);
Log.d("LoginRequestBody",requestBody.getLoginId());
return mSamparkService.performLogin(requestBody)
.flatMap(new Func1<Response<LoginResponse>, Observable<LoginResponse>>() {
#Override
public Observable<LoginResponse> call(Response<LoginResponse> response) {
//TODO: remove sensitive debug logs
Timber.d("status code: %s", response.code());
Timber.d("body: %s", response.body());
Timber.d("error body: %s", response.errorBody());
Timber.d("message: %s", response.message());
try {
Log.d(TAG,"in dtl attnd switch case");
switch (response.code()) {
case 200:
return Observable.just(response.body());
case 401:
case 403:
return Observable.error(new UnauthorizedException(response.errorBody().string()));
default:
return Observable.empty();
}
} catch (IOException e) {
Timber.e(e, "error while signIn");
return Observable.error(e);
}
}
});
}
Error:
Related
Is there any way to handle exceptions in a Flux parallel in case N of X rails fail? I have tried with the onErrorMap, onErrorReturn, and with this try catch, but it keeps throwing error even if all the others are ok, because it is going to the catch of the processRequest method.
protected Object processRequest(RequestHolder requestHolder) {
RequestHolderImpl requestHolderImpl = (RequestHolderImpl) requestHolder;
try {
if (requestHolderImpl.getPayload().getClass().equals(LinkedList.class)) {
payload.addAll((List<DataSourceRequest>) requestHolderImpl.getPayload());
} else {
payload.add((DataSourceRequest) requestHolderImpl.getPayload());
}
List<PurposeResponse> response = Flux.fromIterable(payload)
.parallel()
.flatMap(request -> {
try {
return dataSourceCall(request);
} catch (WebClientResponseException e) {
return Mono.just(new PurposeResponse(request.getPurpose(), buildResponseFromException(e, request.getPurpose())));
} catch (Exception e) {
LOGGER.error("No response could be obtained from DS. Exception thrown: {}", e.getMessage());
return Mono.just(new PurposeResponse(request.getPurpose(), new DataSourceException(e)));
}
})
.sequential()
.collectList()
.block();
return new ResponseHolderImpl(response, products);
} catch (Exception e) {
return new DataSourceException(e.getMessage());
}
}
private Mono<PurposeResponse> dataSourceCall(DataSourceRequest purpose) {
RequestHolder requestHolder = new RequestHolderImpl(purpose,
data,
products,
token);
String purposeName = getPurposeName(requestHolder);
RequestEntity<?> requestEntity = createRequestEntity(requestHolder);
LOGGER.info("Sending request to this url: {}", requestEntity.getUrl());
return webClient.get()
.uri(requestEntity.getUrl())
.header("Authorization", "Bearer " + token)
.retrieve()
.bodyToMono(JsonNode.class)
.elapsed()
.map(data -> {
LOGGER.info("Response took {} milliseconds", data.getT1());
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Response obtained from Data Source: {}", data.getT2());
}
return new PurposeResponse(purposeName, data.getT2());
});
}
private Object buildResponseFromException(WebClientResponseException e, String purposeName) {
//do things
}
API is sending one HTML page as response.
Currently i am receiving as ResponseBody
public interface DashBoardHtmlJsonAPI {
#FormUrlEncoded
#POST("/MobileDashbord")
Call<ResponseBody> getHtml(#Field("UserName") String username, #Field("Password") String password);
}
I want convert the responseBody to String and load the html to webview.
html = response.body().string();
After successful response above code return a blank string
I am not able to retrieve the html page as string.
Retrofit retrofit = new Retrofit.Builder().baseUrl(Constants.BASE_URL).addConverterFactory(ScalarsConverterFactory.create()).build();
DashBoardHtmlJsonAPI dashBoardHtmlJsonAPI = retrofit.create(DashBoardHtmlJsonAPI.class);
Call<ResponseBody> call = dashBoardHtmlJsonAPI.getHtml(userName,password);
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if (response.isSuccessful()){
String html="";
try {
html = response.body().string();
} catch (IOException e) {
e.printStackTrace();
}
loadWebView(html);
Log.i("WEBVIEW",response.toString());
Log.i("WEBVIEW",html);
}
else {
Log.i("WEBVIEW",response.body().toString());
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.i("WEBVIEW",t.getLocalizedMessage());
}
});
Can anybody help me ?
You need to retrieve the content from body
try {
html = response.body().content();
} catch (IOException e) {
e.printStackTrace();
}
My API returns this when I use wrong login information (using postman):
{
"error": {
"statusCode": 401,
"name": "Error",
"message": "login failed",
"code": "LOGIN_FAILED",
"stack": "Error: login failed\n at ...path..."
}
}
I am using this method to get the response message:
private void handleResponse(retrofit2.Response<Response> response) {
if (response.isSuccessful()) {
emailField.setText(null);
passwordField.setText(null);
Intent intent = new Intent(getActivity(), MainActivity.class);
startActivity(intent);
} else {
try {
showSnackBarMessage(response.errorBody().string());
} catch (Exception e) {
showSnackBarMessage(e.getMessage());
}
}
}
And the output (what snackbar shows) is the same as postman returns.
handleresponse parameter retrofit2.Response<Response> response consists of retrofit2 Response, and my own <Response> class which looks like this:
public class Response {
#SerializedName("message")
#Expose
private String message;
public String getMessage() {
return message;
}
}
How can I get only message to show in snackbar?
I have tried the following code, but I get only No value for message.
try {
JSONObject jObjError = new JSONObject(response.errorBody().string());
Toast.makeText(getContext(), jObjError.getString("message"), Toast.LENGTH_LONG).show();
} catch (Exception e) {
Toast.makeText(getContext(), e.getMessage(), Toast.LENGTH_LONG).show();
}
According to your json the response error body is an object with a field error which contains a field message. This means you first need to get the error object and then the message:
JSONObject jObjError = new JSONObject(response.errorBody().string()).getJSONObject("error");
Toast.makeText(getContext(), jObjError.getString("message"), Toast.LENGTH_LONG).show();
I have a method:
public void getVmsAdminToken(HttpClient httpClient, handler<AsyncResult<String>> handler) {
httpClient.postAbs(url, h -> h.bodyHandler(bh -> {
try {
switch (h.statusCode()) {
case 200:
JsonObject vmsResponse = bh.toJsonObject();
handler.handle(Future.succeededFuture(Json.encode(vmsResponse)));
break;
default:
LOG.error("VMS call failed {}", h.statusCode());
handler.handle(Future.failedFuture(500 + ""));
break;
}
} catch (Throwable t) {
LOG.error("Exception in getVmsAdminToken", t);
handler.handle(Future.failedFuture(500 + ""));
}
}))
.setTimeout(timeOutMs)
.putHeader("content-type", "application/json")
.putHeader("stub", apiKey)
.end(vehicleReqBody.encode());
}
I use this inside the following method call :
private void getAdminToken(RoutingContext ctx, RedisFleetStorage storage, HttpClient httpClient) {
getVmsAdminToken(fleetId, user, vehicle, httpClient, replyVms -> {
if (reply.succeeded()) {
// why succeeded?!!
}
});
}
And even if the getVmsToken fails, the execution falls into the if (reply.succeeded())
Why might that be?
You should check the same AsyncResult object being the result of your HTTP call:
private void getAdminToken(RoutingContext ctx, RedisFleetStorage storage, HttpClient httpClient) {
getVmsAdminToken(fleetId, user, vehicle, httpClient, replyVms -> {
if (replyVms.succeeded()) {
// do you thing
}
});
}
On the change "SortBy", my program will do a NetworkIO to retrieve the top movies and display them.
However, it seems that though I have done subscribeOn(Schedulers.io()), the NetworkIO MovieDB.getPopular() and MovieDB.getTopRated() in the function call in map are excuted on the main thread and I get a android.os.NetworkOnMainThreadException.
I was wondering how to make the public Movie[] call(SortBy sortBy) asynchronous.
sortObservable.map(new Func1<SortBy, Movie[]>() {
#Override
public Movie[] call(SortBy sortBy) {
try {
switch (sortBy) {
case POPULAR:
return MovieDB.getPopular(); // NETWORK IO
case TOP_RATED:
return MovieDB.getTopRated(); // NETWORK IO
}
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
return new Movie[0];
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<Movie[]>() {
#Override
public void call(Movie[] movies) {
imageAdapter.loadData(movies);
}
});
Please check if the below works for you. It uses flatMap instead of map.
sortObservable.flatMap(new Func1<SortBy, Observable<Movie[]>>() {
#Override
public Observable<Movie[]> call(SortBy sortBy) {
try {
switch (sortBy) {
case POPULAR:
return Observable.just(MovieDB.getPopular()); // NETWORK IO
case TOP_RATED:
return Observable.just(MovieDB.getTopRated()); // NETWORK IO
}
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
return Observable.just(new Movie[0]);
}
}).subscribe(new Action1<Movie[]>() {
#Override
public void call(Movie[] movies) {
imageAdapter.loadData(movies);
}
});
From your source code on Github, it seems like you are using synchronous mode of executing requests using OkHttp. OkHttp also supports asynchronous requests and that can be preferred. Below would be the changes required in few of the methods.
run method should consume enqueue instead of execute.
Observable<String> runAsync(String url){
return Observable.create(subscriber -> {
Request request = new Request.Builder().url(url).build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onResponse(Call call, Response response) throws IOException {
subscriber.onNext(response.body().string());
}
#Override
public void onFailure(Call call, IOException e) {
subscriber.onError(e);
}
});
});
}
getApi can return an Observable<Movie[]> instead of Movie[]
public Observable<Movie[]> getApiAsync(String type){
return runAsync("http://api.themoviedb.org/3/movie/" + type
+ "?api_key=412e9780d02673b7599233b1636a0f0e").flatMap(response -> {
Gson gson = new Gson();
Map<String, Object> map = gson.fromJson(response,
new TypeToken<Map<String, Object>>() {
}.getType());
Movie[] movies = gson.fromJson(gson.toJson(map.get("results")),
Movie[].class);
return Observable.just(movies);
});
}
Finally I sort it out by myself:
sortObservable.flatMap(new Func1<SortBy, Observable<Movie[]>>() {
#Override
public Observable<Movie[]> call(SortBy sortBy) {
switch (sortBy) {
case POPULAR:
return Observable.fromCallable(() -> MovieDB.getPopular()).subscribeOn(Schedulers.io());
case TOP_RATED:
return Observable.fromCallable(() -> MovieDB.getTopRated()).subscribeOn(Schedulers.io());
default:
return Observable.fromCallable(() -> new Movie[0]).subscribeOn(Schedulers.io());
}
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<Movie[]>() {
#Override
public void call(Movie[] movies) {
imageAdapter.loadData(movies);
}
});