How to get AsyncHttpResponseHandler response as a JSONObject? - java

My Java Restful service login method returns a JSONObject (with name, username, and so on) in a ResponseBuilder entity. I'm trying to get it inside an AsyncHttpResponseHandler (using loopj) in my Android app. The problem is: the onSuccess method expecting a byte[] response, not a JSONObject. How to get the JSONObject inside onSuccess method in order to use it's values (user data) on my app?
Here is my code:
My Restful API login method
public Response login(#Context HttpHeaders httpHeaders,
#FormParam("username") String username,
#FormParam("password") String password) {
Authenticator authenticator = Authenticator.getInstance();
String serviceKey = httpHeaders
.getHeaderString(HTTPHeaderNames.SERVICE_KEY);
try {
// My login method returns an JSONObject with data of the logged user
JSONObject obj = authenticator
.login(serviceKey, username, password);
return getNoCacheResponseBuilder(Response.Status.OK).entity(obj)
.build();
} catch (final LoginException ex) {
return getNoCacheResponseBuilder(Response.Status.UNAUTHORIZED)
.entity(ex.getMessage()).build();
}
}
Login method on my app:
private void loginTask(RequestParams params){
AppRestClient.post("access/login", params, new AsyncHttpResponseHandler() {
#Override
public void onSuccess(int statusCode, Header[] headers, byte[] response) {
// Here I want to get the JSONObject, but response is
// returning something like [B#653abba
Log.d(TAG, response);
}
...
}
Should I transform byte[] into JSONObject (if yes, how can I do that?) or should I change my ResponseBuilder entity to return something different than a JSONObject?
I already tried to use the JsonHttpResponseHandler class but the response is empty.

Related

How to upload video file with extra string values in body, using Retrofit in Java?

I have to upload video file to Server using API, I am using Retrofit. I tried Multipart (by using different approaches) but failed.
I have to upload a video file, reference key as a string and url as a string (in body). In header, I have to upload token.
First I tried this:
Interace:
#Multipart
#POST(url)
Call<LivenessRequest> requestFun(#Header("Authorization") String token,
#Part("reference") RequestBody referenceId,
#Part("url") RequestBody url,
#Part("file") RequestBody videoFile);
Making RequestBody Objects:
RequestBody fileBody;
RequestBody referenceBody;
RequestBody urlBody;
fileBody = RequestBody.create(okhttp3.MediaType.parse("video/*"), videoFile);
referenceBody = RequestBody.create(okhttp3.MediaType.parse("text/plain"), String.valueOf(
"refernce_id_here"));
urlBody = RequestBody.create(okhttp3.MediaType.parse("text/plain"), String.valueOf(
"www.google.com"));
calling API:
interface().requestFun(token,
referenceBody, urlBody, videoFileBody).enqueue(new retrofit2.Callback<request>() {
#Override
public void onResponse(retrofit2.Call<request> call, Response<request> response) {
}
#Override
public void onFailure(retrofit2.Call<request> call, Throwable t) {
}
});
I tried it with another approach that is:
Interface:
#Multipart
#POST(url)
Call<LivenessRequest> requestFun(#Header("Authorization") String token,
#Body RequestBody body);
Making RequestBody Object:
RequestBody body = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("file",videoFile.getName(),
RequestBody.create(MediaType.parse("application/octet-stream"), videoFile))
.addFormDataPart("url","www.google.com")
.addFormDataPart("reference", reference)
.build();
API calling:
interface().requestFun(token, body).enqueue(new retrofit2.Callback<request>() {
#Override
public void onResponse(retrofit2.Call<request> call, Response<request> response) {
}
#Override
public void onFailure(retrofit2.Call<request> call, Throwable t) {
}
});
Postman Screenshot of this api is attached:

OkHttpClient authenticator without retrofit

Im trying to refresh an Access token in my application following this solution.
My actual problem is handling the callback and then return the new request in the authenticate method.
I tried using an interface to return a String from my callback method but then I cant assign it to a variable, nor can I return the new request from there since its inside my onResponseListener.
How can I solve this issue?
public Request authenticate(Route route, Response response) throws IOException {
// GetAuthRequest is a void method, and I cant assign a String value on the callback.
getAuthRequest(new AuthResponse() {
#Override
public Request onSuccess(String token) {
return response.request().newBuilder()
.header("Authorization", "Bearer " + token)
.build();
}
});
I was using an Asynchronous call instead of Synchronous. Ended up making a method that returns an String like so:
private String getAuthRequest() {
// Make the request above
try (Response response = httpClient.newCall(request).execute()) {
JSONObject jsonObject = new JSONObject(response.body().string());
return jsonObject.getString("access_token");
} catch (IOException | JSONException e) {
e.printStackTrace();
}
return null;
}

How to extract data from HashMap<String, Object> in Retrofit2?

I have Spring Boot project on backend and Android app on frontend. Communication between the two happens via Retrofti2. On one of the endpoits, actually /login endpoint, is retruning a HashMap<String, Object>. That endpoint looks like this:
#RequestMapping(value = "/login", method = RequestMethod.POST)
public ResponseEntity<?> login(#RequestBody AuthenticationRequest authenticationRequest) throws Exception {
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("user", getUserObject());
map.put("token", getJwtToken());
return ResponseEntity.ok(map);
}
Interface for method call looks like this:
public interface LoginService {
#POST("login")
Call<HashMap<String, Object>> testLogin(#Body Login login); //login contains username and password strings
}
The reposnse in frontend look like this:
Call<HashMap<String, Object>> call = mLoginService.testLogin(new Login(username, password));
call.enqueue(new Callback<HashMap<String, Object>>() {
#Override
public void onResponse(Call<HashMap<String, Object>> call, Response<HashMap<String, Object>> response) {
if (!response.isSuccessful()){
Toast.makeText(getApplicationContext(), "Wrong credentials!", Toast.LENGTH_SHORT).show();
return;
}
//extract user & token
HashMap<String, Object> map = response.body();
Log.i("Test result", map.get("token").toString());
Log.i("Test result", map.get("user").toString());
User u = (User) map.get("user");
//Toast.makeText(getApplicationContext(), "Welcome " + u.getUsername() + "!", Toast.LENGTH_SHORT).show();
startActivity(goToEmailsIntent);
}
#Override
public void onFailure(Call<HashMap<String, Object>> call, Throwable t) {
Toast.makeText(getApplicationContext(), "Cannot login, look at the console", Toast.LENGTH_SHORT).show();
Log.i("ERRROOOOOOR during login", t.toString());
return;
}
});
When I look at the log statements in the console everything is okey, I get the data which I want. But when trying to cast to User object I get exception.
java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to com.example.email.model.User
How to get around this? Is there any better way to send User object and a String from backend?
First method
When you can change your backend service then modify the backend service return DTO not HashMap.
#RequestMapping(value = "/login", method = RequestMethod.POST)
public ResponseEntity<Token> login(#RequestBody AuthenticationRequest authenticationRequest) throws Exception {
// create your response
Token token = new Token();
return ResponseEntity.ok(token);
}
Second method
Use json format to exchange data,in your onResponse method you can do like below:
HashMap<String, Object> map = response.body();
// map.get("user) may return a null value
String jsonString = new Gson().toJson(map.get("user));
User user = new Gson().fromJson(jsonString,User.class);
// do other thing as you want

Volley GET JsonObjectRequest with JSONObjectParameter doesn't work at all

I've got a problem with Volley request - I want to send GET (another similiar POST also) request with JSONObject param (user having password and login) to authorize user and send back full user data. Although I can see during debugging that mRequestBody is correct JSON but I cannot receive it by my controller -
private void processLogin() throws JSONException {
this.user.setLogin(this.loginText.getText().toString());
this.user.setPassword(this.passwordText.getText().toString());
final JSONObject jsonObject = new JSONObject(new Gson().toJson(this.user));
final JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, UrlHelper.loginUrl, jsonObject, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
user = new Gson().fromJson(response.toString(), User.class);
if (user.getUserId().equals(getResources().getString(R.string.ERROR))) {
onLoginFailed();
} else {
onLoginSuccess(user);
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d(TAG, error.toString());
}
}) {
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> headers = new HashMap<String, String>();
headers.put("Content-Type", "application/json");
return headers;
}
};
VolleySingleton.getInstance(this).addToRequestQueue(request);
}
Controller method:
#RequestMapping(value = "/loginTest", method = RequestMethod.GET, produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
public User someMethod(#RequestBody User user) throws SQLException {
return userService.authenticateUser(user.getLogin(), user.getPassword());
}
Without annotation #RequestBody I it process but User in param is empty, so I process User with null password and login. Recently I did it by StringRequest Please, help me. :)
As a part of the HTTP specs, GET requests have no body. You can create and send GET requests with a body though, but that's meaningless since the body has no semantic meaning in the GET method specification. I don't know too much about Spring, but my guess is that Spring is probably ignoring the body of the request because it's a GET method. You should send and receive the request as POST if your intention is to put something inside the body.

How can I return a value from a function that uses json response?

I have implemented function to get the restaurant area minimum order. In check_minimum_order() function, I have got desired result from the response. The value is rest_area_min_order = 10. Now, I want to pass the value which I received through JSON to the next function So that I can do calculation part.
Here is the code of check_minimum_order()
private void check_minimum_order(String restaurant_id)
{
try
{
String url;
if(appPrefs.getLanguage().equalsIgnoreCase("ar"))
url = LinksConstants.BASE_URL
+ LinksConstants.CHECK_MINIMUM_ORDER;
else
url = LinksConstants.BASE_URL
+ LinksConstants.CHECK_MINIMUM_ORDER;
RequestParams params = new RequestParams();
params.put("restaurant_id", restaurant_id);
params.put("area_id", city_id);
NetworkRestClient.post(url, params, new JsonHttpResponseHandler() {
#Override
public void onStart() {
super.onStart();
progressActivity.showLoading();
}
#Override
public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
super.onSuccess(statusCode, headers, response);
try
{
if (response != null)
{
rest_area_min_order = response.getString("restaurant_area_min_order");
}
}
catch (Exception ex)
{
GSLogger.e(ex);
showError();
}
}
#Override
public void onFailure(int statusCode, Header[] headers, String errorResponse, Throwable throwable) {
super.onFailure(statusCode, headers, errorResponse, throwable);
showError();
if(AppConstants.DEBUG_MODE)
showToast(errorResponse);
}
#Override
public void onFailure(int statusCode, Header[] headers, Throwable throwable, JSONObject errorResponse) {
super.onFailure(statusCode, headers, throwable, errorResponse);
showError();
}
});
}
catch (Exception ex)
{
GSLogger.e(ex);
showError();
}
}
Now, the above check_minimum_order() function gave me the value of rest_area_min_order as 10. Now, I want to use this rest_area_min_order in another function. Here is the code: `
check_minimum_order(restaurant_id);
HashMap<String, Object> items_hash = (HashMap<String, Object>) rest_cart_hash.get(restaurant.getId());
items_hash.put("delivery_pickup_time", time);
items_hash.put("pickup_address_id", pickup_id);
items_hash.put("payment_method_id", payment_id);
items_hash.put("delivery_pickup", delivery_pickup);
items_hash.put("selected_user_address_id", user_address_id);
items_hash.put("rest_area_min_order", rest_area_min_order);
restaurantList.add(items_hash);
String rest_min_order = (String) items_hash.get("rest_min_order");
String rest_subtotal = (String) items_hash.get("rest_subtotal");
String rest_area_min_order = (String) items_hash.get("rest_area_min_order");
boolean isError = isValidMinOrderAmount(rest_min_order, rest_subtotal, rest_area_min_order);`
Basically your onSuccess function return void so you cannot return anything. You can simply call another function in onSuccess (For example setMinimumOrder(int pMinimumOrder)) which will take rest_area_min_order as a input and you can perform rest of the things as per your requirement.
As Far as I know, there are two options to achieve this.
1) Put the code to be executed, directly in onSuccess after getting the value of rest_area_min_order. Or you can create a separate method for that.
2) Using Interface to pass value.
I prefer the first option which is very simple.
From your question, I understand that you have to do some calculation after getting web service response. If the rest of calculation needs to done in same class then call that method after getting response
if (response != null)
{
rest_area_min_order = response.getString("restaurant_area_min_order");
doPostCalculations(rest_area_min_order);
}
If check_minimum_order() method is in Network class and you are calling this method from another class (eg: activity), then you can communicate back to activity(or the class that called the method) using interface on getting the response.
Here is a sample interface that you can use.
public interface ApiListener {
void onSuccess(JSONObject response);
void onFailure();
}
Please have a look at this post for getting more idea about interface - How to create our own Listener interface in android?
The main reason is that in your check_minimum_order method you post your networking to another thread if you wan to do some work with the result returned from network then you must call it in on success after the result is really fetched.

Categories

Resources