I am using retrofit to handle the API calls but facing problem while posting long JSON. I am getting:
internal server error(code : 500)
I need to convert post params to below format.
Body :
{"UserId" : "2",
"PortalId" : "1",
"LocaleId" : "1",
"CatalogId" : "3",
"Items" : [{"Name" : "ap1234","Quantity" : "1"}]}
Below is the code I am using
Api Call :
JSONArray array = new JSONArray();
try {
JSONObject jsonObject1 = new JSONObject();
jsonObject1.put("Name", "ap1234");
jsonObject1.put("Quantity", "1");
array.put(jsonObject1);
} catch (JSONException e) {
e.printStackTrace();
}
Call data = mApiInterface.getData("application/json","2", "1", "1", "3", array.toString());
addToCart.enqueue(new Callback<DataResponse>() {
Retrofit Interface :
#FormUrlEncoded
#POST(API_ADD_TO_CART)
Call<DataResponse> getData(#Header("Content-Type") String contentType, #Field("UserId") String userId,
#Field("LocaleId") String localeId,
#Field("PortalId") String portalId,
#Field("CatalogId") String CatalogId,
#Field("Items") String Items);
#Body String body has to be used.
JSONArray array = new JSONArray();
try {
JSONObject jsonObject1 = new JSONObject();
jsonObject1.put("Name", "ap1234");
jsonObject1.put("Quantity", "1");
/*
create a json object pass as body
{"UserId" : "2",
"PortalId" : "1",
"LocaleId" : "1",
"CatalogId" : "3",
"Items" : [{"Name" : "ap1234","Quantity" : "1"}]}
*/
array.put(jsonObject1);
} catch (JSONException e) {
e.printStackTrace();
}
Call data = mApiInterface.getData("application/json","2", "1", "1",
"3", array.toString());
addToCart.enqueue(new Callback<DataResponse>() {
change as following
#FormUrlEncoded
#POST(API_ADD_TO_CART)
Call<DataResponse> getData(#Header("Content-Type") String contentType, #Body String body);
Try using the #Body annotation .
Create a User class add your data to that instance and with retrofit instead of using #field you should send #Body with the User class as body .
example:
interface Foo {
#POST("/jayson")
FooResponse postRawJson(#Body TypedInput body);
}
For more info I found this link to be helpful
https://futurestud.io/tutorials/retrofit-send-objects-in-request-body
retrofit is too typical to implement and this is the easiest method I ever used for retrofit.
public void sendPost(String s1) {
dialog.setMessage("Please wait...");
dialog.setCancelable(false);
dialog.show();
apiService.getData(s1).enqueue(new Callback<JsonObject>() {
#Override
public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
dialog.dismiss();
try {
if (response != null) {
JSONObject jsonObject = new JSONObject(response.body().toString());
String status = jsonObject.optString("status");
}
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void onFailure(Call<JsonObject> call, Throwable t) {
if (dialog != null) {
if (dialog.isShowing()) {
dialog.dismiss();
}
}
}
});
}
I don't think #Header("Content-Type") String contentType is useful in api services, just use #Field to send request
#POST("list_data")
#FormUrlEncoded
Call<JsonObject> shopList(#Field("string") String string);
Thanks for the help guys I did it using #Body
#POST(API_ADD_TO_CART)
Call<ShoppingCartResponse> getData(#Header("Content-Type") String contentType, #Body DataRequest request)
public class AddToCartRequest {
#SerializedName("UserId")
#Expose
private String userId;
#SerializedName("PortalId")
#Expose
private String portalId;
#SerializedName("LocaleId")
#Expose
private String localeId;
#SerializedName("CatalogId")
#Expose
private String catalogId;
#SerializedName("Items")
#Expose
private List<Items> items = null;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getPortalId() {
return portalId;
}
public void setPortalId(String portalId) {
this.portalId = portalId;
}
public String getLocaleId() {
return localeId;
}
public void setLocaleId(String localeId) {
this.localeId = localeId;
}
public String getCatalogId() {
return catalogId;
}
public void setCatalogId(String catalogId) {
this.catalogId = catalogId;
}
public List<Item> getItems() {
return items;
}
public void setItems(List<Item> items) {
this.items = items;
}
}
Related
I'm trying to display my row tables on the database in my ListView , However I dont know how to convert JSONObject to JSONArray and set it to my setter class. I get my JSON through Volley String Request
I have the JSON output like this :
{
"error": false,
"message": "Status Fetched",
"status": [
{
"OrderCode": "5x2azu",
"GuestName": "Try",
"ProductName": "Mie Ayam Super Jumbo Komplit",
"ProductType": "Kuah",
"NoTable": 4,
"Status": "Disiapkan",
"TotalPrice": "58000"
},
{
"OrderCode": "etent3",
"GuestName": "Try",
"ProductName": "Nasi Soto Daging Sapi",
"ProductType": "Soto",
"NoTable": 4,
"Status": "Disiapkan",
"TotalPrice": "27000"
},
{
"OrderCode": "ro1eyx",
"GuestName": "Try",
"ProductName": "Mie Ayam Original",
"ProductType": "Kuah",
"NoTable": 4,
"Status": "Disiapkan",
"TotalPrice": "23000"
}
]
}
and here is my String Request :
public void StringRequest() {
StringRequest stringRequest = new StringRequest(Request.Method.POST, URLs.STATUS,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
JSONObject obj = new JSONObject(response);
Toast.makeText(getContext(), response, Toast.LENGTH_SHORT).show();
//if no error in response
if (!obj.getBoolean("error")) {
Toast.makeText(getContext(), obj.getString("message"), Toast.LENGTH_SHORT).show();
//getting Status from response
JSONObject statusJson = obj.getJSONObject("status");
Status status = new Status(
statusJson.getString("OrderCode"),
statusJson.getString("GuestName"),
statusJson.getString("ProductName"),
statusJson.getString("ProductType"),
statusJson.getString("NoTable"),
statusJson.getString("Status"),
statusJson.getString("TotalPrice")
);
} else {
Toast.makeText(getContext(), obj.getString("message"), Toast.LENGTH_SHORT).show();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(getContext(),error.getMessage(),Toast.LENGTH_SHORT).show();
}
}) {
#Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String,String> params = new HashMap<>();
params.put("tablecode",TableCode);
return params;
}
};
VolleySingleton.getInstance(getContext()).addToRequestQueue(stringRequest);
}
I dont know how to convert it from JSONObject to JSONArray
here is my Setter and getter class
package com.example.pesanpalgading20.Getter.Status;
import java.util.ArrayList;
public class Status {
private String OrderCode,Name,FoodName,TypeFood,NoTable,Status,TotalPrice;
public Status(){
}
public Status(String orderCode, String name, String foodName, String typeFood, String noTable, String status, String totalPrice) {
OrderCode = orderCode;
Name = name;
FoodName = foodName;
TypeFood = typeFood;
NoTable = noTable;
Status = status;
TotalPrice = totalPrice;
}
public String getOrderCode() {
return OrderCode;
}
public void setOrderCode(String orderCode) {
OrderCode = orderCode;
}
public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
public String getFoodName() {
return FoodName;
}
public void setFoodName(String foodName) {
FoodName = foodName;
}
public String getTypeFood() {
return TypeFood;
}
public void setTypeFood(String typeFood) {
TypeFood = typeFood;
}
public String getNoTable() {
return NoTable;
}
public void setNoTable(String noTable) {
NoTable = noTable;
}
public String getStatus() {
return Status;
}
public void setStatus(String status) {
Status = status;
}
public String getTotalPrice() {
return TotalPrice;
}
public void setTotalPrice(String totalPrice) {
TotalPrice = totalPrice;
}
}
so how do I set the value of the each JSON to SetterandGetter class ?
try {
JSONObject obj = new JSONObject(response);
//if no error in response
if (!obj.getBoolean("error")) {
//getting Status from response
JSONArray statusJson = obj.getJSONArray("status");
for (int i = 0; i < statusJson.length(); i++) {
Status status = new Status(
statusJson.getJSONObject(i).getString("OrderCode"),
statusJson.getJSONObject(i).getString("GuestName"),
statusJson.getJSONObject(i).getString("ProductName"),
statusJson.getJSONObject(i).getString("ProductType"),
statusJson.getJSONObject(i).getString("NoTable"),
statusJson.getJSONObject(i).getString("Status"),
statusJson.getJSONObject(i).getString("TotalPrice")
);
// Add Status In your Array list and enjoy
}
} else {
Toast.makeText(getContext(), obj.getString("message"), Toast.LENGTH_SHORT).show();
}
} catch (JSONException e) {
e.printStackTrace();
}
You can use Gson library and convert your json to a model class
To do it first you have to add gson as a dependancy
implementation "com.google.code.gson:gson:2.8.6"
And then since your status in json is array use it like this
JSONArray status = obj.getJSONArray("status");
//Code to convert json array to arraylist of object
Arraylist<Status> arraylist = Gson().fromJson(
status.toString(),
new TypeToken<ArrayList<Status>>(){}.getType()
)
Above code will store your json array status to arraylist variable
so the gettin JSON array is completed but it still display one list from the array this is the code
public void StringRequest() {
StringRequest stringRequest = new StringRequest(Request.Method.POST, URLs.STATUS,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
JSONObject obj = new JSONObject(response);
Toast.makeText(getContext(), response, Toast.LENGTH_SHORT).show();
//if no error in response
if (!obj.getBoolean("error")) {
Toast.makeText(getContext(), obj.getString("message"), Toast.LENGTH_SHORT).show();
//getting Status from response
JSONArray statusJson = obj.getJSONArray("status");
for (int i = 0; i < statusJson.length(); i++) {
Status status = new Status(
statusJson.getJSONObject(i).getString("OrderCode"),
statusJson.getJSONObject(i).getString("GuestName"),
statusJson.getJSONObject(i).getString("ProductName"),
statusJson.getJSONObject(i).getString("ProductType"),
statusJson.getJSONObject(i).getString("NoTable"),
statusJson.getJSONObject(i).getString("Status"),
statusJson.getJSONObject(i).getString("TotalPrice")
);
ArrayList<Status> statusList = new ArrayList<Status>();
statusList.add(status);
statusAdapter = new StatusAdapter(getActivity(),statusList);
StatusListView.setAdapter(statusAdapter);
}
} else {
Toast.makeText(getContext(), obj.getString("message"), Toast.LENGTH_SHORT).show();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(getContext(),error.getMessage(),Toast.LENGTH_SHORT).show();
}
}) {
#Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String,String> params = new HashMap<>();
params.put("tablecode",TableCode);
return params;
}
};
VolleySingleton.getInstance(getContext()).addToRequestQueue(stringRequest);
}
I dont know where to put the increment in the setting adapter in
statusList.add(status);
edit : It solved! Thanks to #Pratik Fagadiya
I put the setting adapter outside of the loop and it worked and added more than 1 list
I have some JSON response need to find a way to parse the token from the data
{
"status": true,
"message": "Logged in successfully",
"error_code": 0,
"result": {
"token": "eyJ0eXAiOiJBdXRoIiwiYWxnIjoiSFMyNTYifQ.eyJpYXQiOjE1NzEyODczNjEsImV4cCI6MTU3MTM3Mzg2MSwicGF5bG9hZCI6eyJ1c2VyX2lkIjoiMTAxIiwiY29tcGFueV9pZCI6IjEifX0.-BEWhUT762rkcdZCBG6gU8q52AhITUm_kPazh1Tsj78",
"unique_id": "101",
"first_name": "AAA",
"last_name": "R",
"user_groups_sites": [
{
"group_id": "6",
"group_name": "Zonal Manager",
"group_key": "zonal_manager",
"sites": [
{
"site_id": "1",
"site_name": "AAAA"
}
]
},
{
"group_id": "5",
"group_name": "Auditor",
"group_key": "auditor",
"sites": [
{
"site_id": "1",
"site_name": "AAAAA"
}
]
}
]
}
}
Sol 1:
JSONObject jsonObject = null;
try {
jsonObject = new JSONObject(response);
JSONObject myResponse = jsonObject.getJSONObject("result");
String mToken = (String) myResponse.getString("token");
Log.e("result", myResponse.toString());
JSONArray userGroupsSites = myResponse.getJSONArray("user_groups_sites");
for (int i = 0; i < userGroupsSites.length(); i++) {
JSONObject sites = userGroupsSites.getJSONObject(i);
Log.e("actor", sites.toString());
JSONArray getSiteObject = sites.getJSONArray("sites");
JSONObject siteValue = getSiteObject.getJSONObject(0);
Log.e("siteValue", siteValue.toString());
String getSiteId = (String) siteValue.getString("site_id");
String getSiteName = (String) siteValue.getString("site_name");
System.out.println("Site Id: " + getSiteId);
System.out.println("Site Name: " + getSiteName);
}
} catch (JSONException e) {
e.printStackTrace();
}
Sol:2 Create a model class:
Model.java
public class Model {
private boolean status;
private String message;
ResultData result;
public boolean isStatus() {
return status;
}
public void setStatus(boolean status) {
this.status = status;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public ResultData getResult() {
return result;
}
public void setResult(ResultData result) {
this.result = result;
}
public class ResultData {
private String token;
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
}
}
API call should be:
call.enqueue(new Callback<Model>() {
#Override
public void onResponse(#NonNull Call<Model> call, #NonNull Response<Model> response) {
System.out.println(response.body().getResult().getToken());
}
#Override
public void onFailure(#NonNull Call<Model> call, #NonNull Throwable t) {
t.printStackTrace();
}
});
This will work fine.
you can parse your json response by doing this first get the main json object and then get the first object called result .
JSONObject jsonobject = new JSONObject(response);
JSONObject resultObject = jsonobject.getJSONObject("result");
String token = resultObject.getString("token");
I want to print my Error from onErrorResponse using volley in android, i want to print them separately in different textview.
my error from onErrorResponse
{
"message": "422 Unprocessable Entity",
"error": {
"username": [
"The username has already been taken."
],
"email": [
"The email has already been taken."
]
},
"status_code": 422
}
so i want to print them separately,
i mean The username has already been taken. in one textview and The email has already been taken. in 2nd textview. thank
My Code:
public void postData(JSONObject jsonObject) {
String url = "http://www.xxxxxxxx.com/api/v1/auth/register";
String REQUEST_TAG = "volley_key";
JsonObjectRequest jsonObjectReq = new JsonObjectRequest(Request.Method.POST, url, jsonObject,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
verifyResponse(response);
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
NetworkResponse networkResponse = error.networkResponse;
if (networkResponse != null && networkResponse.data != null) {
String errorStr = new String(networkResponse.data);
try {
JSONObject jObj = new JSONObject(errorStr);
JSONObject objError = jObj.getJSONObject("error");
JSONArray emailArray = objError.getJSONArray("email");
if (emailArray != null) {
String emailMessage = String.valueOf(emailArray.get(0));
Toast.makeText(getApplication(), emailMessage, Toast.LENGTH_LONG).show();
}
JSONArray usernameArray = objError.getJSONArray("username");
if (usernameArray != null) {
String usernameMessage = String.valueOf(emailArray.get(0));
Toast.makeText(getApplication(), usernameMessage, Toast.LENGTH_LONG).show();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
}){
#Override
protected VolleyError parseNetworkError(VolleyError volleyError) {
if (volleyError.networkResponse != null && volleyError.networkResponse.data != null) {
VolleyError error = new VolleyError(new String(volleyError.networkResponse.data));
volleyError = error;
}
return volleyError;
}
}; VolleySingleton.getInstance(getApplicationContext()).addToRequestQueue(jsonObjectReq, REQUEST_TAG);
}
Add there ErrorModel.class and Error class into java folder.
package co.exmaple;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class ErrorModel {
#SerializedName("message")
#Expose
private String message;
#SerializedName("error")
#Expose
private Error error;
#SerializedName("status_code")
#Expose
private Integer statusCode;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Error getError() {
return error;
}
public void setError(Error error) {
this.error = error;
}
public Integer getStatusCode() {
return statusCode;
}
public void setStatusCode(Integer statusCode) {
this.statusCode = statusCode;
}
}
Erro.class
package co.exmaple;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Error {
#SerializedName("name")
#Expose
private List<String> name = null;
#SerializedName("username")
#Expose
private List<String> username = null;
#SerializedName("email")
#Expose
private List<String> email = null;
public List<String> getName() {
return name;
}
public void setName(List<String> name) {
this.name = name;
}
public List<String> getUsername() {
return username;
}
public void setUsername(List<String> username) {
this.username = username;
}
public List<String> getEmail() {
return email;
}
public void setEmail(List<String> email) {
this.email = email;
}
}
Then in StringError Request set Error text into texView.
StringRequest stringRequest = new StringRequest(url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
GsonBuilder gsonBuilder = new GsonBuilder();
Gson gson = gsonBuilder.create();
ErrorModel error = gson.fromJson(response,ErrorModel.class);
recyclerView.setAdapter(new ErrorAdapter(ErrorActivity.this,error.getError));
}
});
RequestQueue requestQueue = Volley.newRequestQueue(this);
requestQueue.add(stringRequest);
Make RecyclerView adapter to set Error text to TextView
you can check for the keys inside error object and simply can check if the key exists then show the error for particular Textview.
here is the example.I am taking a case where you are using JsonObject class of volley i.e, the response is in JsonObject.
JsonObject obj=response.getAsJsonObject("error");
if(obj.has("name")){
nameTextView.setText(obj.getAsJsonArray("name").get(0)+"");
}
if(obj.has("username")){
usernameTextView.setText(obj.getAsJsonArray("username").get(0)+"");
}
if(obj.has("email")){
emailTextView.setText(obj.getAsJsonArray("email").get(0)+"");
}
I am using Volleyin my project for handling network requests. Here is a sample JSON my server returns
JSON Object Response
{"code":"success", "data":{"some data"}}
JSON Array Response
{"code":"success", "data":["some data"]}
When some validation error or any other error occurs, server returns following response:
{"code":"failed", "error":"Access denied"}
The problem is with parsing data. when request is successful, in onResponse of ResponseListener, I simply get the content of data key. Where as, I was expecting the result same as what I posted above. I am not getting why Volley is returning only content of data and not complete JSON. I had used Volley earlier also. But never faced such type of problem.
Parsing Code:
private void getOnboardingCategories() {
Response.Listener<JSONArray> responseListener = new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
Log.d(LOG_TAG, "CATEGORY RESPONSE: " + response.toString());
if (response != null) {
int dataLength = response.length();
for (int i = 0; i < dataLength; i++) {
JSONObject jObject = response.optJSONObject(i);
if (jObject != null) {
CategoryType2 categoryType2 = new CategoryType2();
categoryType2.set_id(jObject.optString("_id"));
categoryType2.setName(jObject.optString("name"));
categoryType2.setApp_icon_data(jObject.optString("thumbnail_data"));
categories.add(categoryType2);
}
}
}
if (isVisible())
sellAdapter.notifyDataSetChanged();
}
};
Response.ErrorListener errorListener = new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
error.printStackTrace();
Util.errorHandler(error, ctx);
}
};
JsonArrayRequest jsonObjectRequest = new JsonArrayRequest(Method.GET, url,
null, responseListener, errorListener);
MyApplication.getInstance().addToRequestQueue(jsonObjectRequest, "onboarding");
}
Response on Success:
{
code: "success",
data: [
{
_id: "55c06b05a3e0041a73cea744",
name: "Test Category 1",
thumbnail_data: "",
},
{
_id: "55c06b16a3e0046108cea744",
name: "Test Category 2",
thumbnail_data: "",
}
]
}
In onResponse of ResponseListener, I get this data:
[
{
_id: "55c06b05a3e0041a73cea744",
name: "Test Category 1",
thumbnail_data: "",
},
{
_id: "55c06b16a3e0046108cea744",
name: "Test Category 2",
thumbnail_data: "",
}
]
When error occurs, server returns this response:
{"code":"failed", "error":"error_msg"}
Due to this, Volley throws ParseException as it expects JSONArray. I need to show the error message to the user. Earlier, I was using AsyncTask and I handled the error there. But, with Volley I am facing difficulty. I looked into VolleyError, but didn't got any clue.
Update 1
private void getOnboardingCategories() {
showSpinnerDialog(true);
Response.Listener<JSONObject> responseListener = new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Log.d(LOG_TAG, "CATEGORY RESPONSE: " + response.toString());
hideSpinnerDialog();
String code = response.optString("code");
if (code.equals("success")) {
if (response != null) {
JSONArray dataArray = response.optJSONArray("data");
int dataLength = dataArray.length();
for (int i = 0; i < dataLength; i++) {
JSONObject jObject = dataArray.optJSONObject(i);
if (jObject != null) {
CategoryType2 categoryType2 = new CategoryType2();
categoryType2.set_id(jObject.optString("_id"));
categoryType2.setName(jObject.optString("name"));
categoryType2.setApp_icon_data(jObject.optString("app_icon_data"));
categories.add(categoryType2);
}
}
}
}
if (isVisible())
sellAdapter.notifyDataSetChanged();
}
};
Response.ErrorListener errorListener = new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
error.printStackTrace();
Util.errorHandler(error, ctx);
}
};
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Method.GET, url,
null, responseListener, errorListener);
MyApplication.getInstance().addToRequestQueue(jsonObjectRequest, "onboarding");
}
Update
This issue was not about Volley. There was issue on the server end wrt gzip compression. I am going to vote for closing this question.
But, when error occurs, I get Parse exception, when making request
for JSONArray
Use JSONObject. has() and JSONObject. isNull() to check which key is present in json response before parsing json.
For Example:
JSONObject jsonObject=new JSONObject(<server_response_string>);
if(jsonObject.has("data") && !jsonObject.isNull("data"))
{
// get data JSONArray from response
}else{
// get message using error key
}
An efficient method to handle this kinda situation can be achieved through parsing JSON values using GSON and assign the key values using POJO class.
Example:
Add error scenario in both the cases like handling JSONArray or JSONObject. Please find the samples of your required POJO for your test data as follows.
Sample 1
public class JSONArrayPojo
{
private ArrayList<String> data;
private String code;
private String error;
public String getError() {
return this.error;
}
public void setError(String value) {
this.error = value;
}
public ArrayList<String> getData ()
{
return data;
}
public void setData (ArrayList<String> data)
{
this.data = data;
}
public String getCode ()
{
return code;
}
public void setCode (String code)
{
this.code = code;
}
}
Sample 2
public class JSONObjectPojo
{
private String data;
private String code;
private String error;
public String getError() {
return this.error;
}
public void setError(String value) {
this.error = value;
}
public String getData ()
{
return data;
}
public void setData (String data)
{
this.data = data;
}
public String getCode ()
{
return code;
}
public void setCode (String code)
{
this.code = code;
}
}
Generating GSON from your response and handling out the both positive(success) and negativ(error) scenario as follows:
#Override
public void onResponse(JSONArray response) {
Log.d(LOG_TAG, "CCMP CATEGORY RESPONSE: " + response.toString());
if (response != null) {
//converting JSON response into GSON Format
JSONArraryPojo jsonArray = null;
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.serializeNulls();
Gson gson = gsonBuilder.create();
jsonArray = gson.fromJson(response.toString(), JSONArraryPojo.class);
if(jsonArray.getCode().equals("success")){
//process your steps if the value is success
Toast.makeText(this, jsonArray.getCode(), Toast.LENGTH_SHORT).show();
}else {
//displaying toast when error occurs
Toast.makeText(this, jsonArray.getError(), Toast.LENGTH_SHORT).show();
}
}
}
};
Reference links to parse into GSON from JSON
http://kylewbanks.com/blog/Tutorial-Android-Parsing-JSON-with-GSON
http://examples.javacodegeeks.com/core-java/json/json-parsing-with-gson/
http://www.javacodegeeks.com/2011/01/android-json-parsing-gson-tutorial.html
http://www.mysamplecode.com/2013/07/android-json-stream-data-parsing.html
http://blog.nkdroidsolutions.com/
Note: To make use of GSON library in android.
Add following lines in gradle:
compile 'org.immutables:gson:2.1.0.alpha'
In case of error your server should return error json with http status code 4xx. That is how you design Restful APIs. In current situation, your API is always returning 2xx which corresponds to successful API result.
If your API sends correct http response code, in this case 401 (unauthorized) or 403 (forbidden) refer here then your ErrorListener will be called by Volley. You don't have to write parsing logic for error response in ResponseListener. Here is a good resource for understanding rest api http status codes.
UPDATE RESULT SCREENSHOTS:
Success case: JSONArray
[
{
"_id": "55c06b05a3e0041a73cea744",
"name": "Category 1",
"thumbnail_data": ""
},
{
"_id": "55c06b16a3e0046108cea744",
"name": "Category 2",
"thumbnail_data": ""
}
]
Error case: JSONObject
{
"code": "failed",
"error": "error_msg"
}
In my code below, pay attention to parseNetworkResponse.
The following is my updated answer, I have tested for both responses you provided:
RequestQueue queue = Volley.newRequestQueue(mContext);
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(0, url, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
if (!response.isNull("success")) {
JSONArray jsonArray = response.getJSONArray("success");
Toast.makeText(mContext, "onResponse:\n\n" + jsonArray.toString(5), Toast.LENGTH_SHORT).show();
if (mTextView != null) {
mTextView.setText(jsonArray.toString(5));
}
} else {
String codeValue = response.getString("code");
if ("failed".equals(codeValue)) {
String errorMessage = response.getString("error");
Toast.makeText(mContext, "Error Message:\n\n" + errorMessage, Toast.LENGTH_SHORT).show();
if (mTextView != null) {
mTextView.setText("Error Message:\n\n" + errorMessage);
}
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(mContext, "onErrorResponse:\n\n" + error.toString(), Toast.LENGTH_SHORT).show();
}
}) {
#Override
protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
try {
String jsonString = new String(response.data,
HttpHeaderParser.parseCharset(response.headers, PROTOCOL_CHARSET));
// Check if it is JSONObject or JSONArray
Object json = new JSONTokener(jsonString).nextValue();
JSONObject jsonObject = new JSONObject();
if (json instanceof JSONObject) {
jsonObject = (JSONObject) json;
} else if (json instanceof JSONArray) {
jsonObject.put("success", json);
} else {
String message = "{\"error\":\"Unknown Error\",\"code\":\"failed\"}";
jsonObject = new JSONObject(message);
}
return Response.success(jsonObject,
HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
} catch (JSONException e) {
return Response.error(new ParseError(e));
}
}
};
queue.add(jsonObjectRequest);
Hope this helps!
You can check the value of code key as it will always be available to you whether the response would be a failure or success. Below is a small snippet:
JSONObject jObj = new JSONObject(your_response_string);
if(jObj.getString("code").equalsIgnoreCase("failed"))
{
//write code for failure....
}
else{
//write code for success......
}
Note: A more modular way to do this is to make a model class and set your values in it. This way you will get all your values in a single java object.
Maybe you can try this:
Use the fastjson library to convert your json string to your java object in Response.Listener like this:
Pojo pojo = JSON.parseObject(response.toString(), Pojo.class);
And your Pojo may like this:
public class Pojo {
private String code;
private String error;
private List<Date> data;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getError() {
return error;
}
public void setError(String error) {
this.error = error;
}
public List<Date> getData() {
return data;
}
public void setData(List<Date> data) {
this.data = data;
}
public class Data {
public String _id;
public String name;
public String thumbnail_data;
public String get_id() {
return _id;
}
public void set_id(String _id) {
this._id = _id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getThumbnail_data() {
return thumbnail_data;
}
public void setThumbnail_data(String thumbnail_data) {
this.thumbnail_data = thumbnail_data;
}
}
}
then what you need to do is to check if your pojo has value such as error,if error is not null ,you need to handle it .
The fastjson library has help you to avoid crash while converting.
you can find fastjson here
Use this code:
onResponse(JSONObject response){
if(response.getString("code").equalIgnoreCase("success")){
try{
JSONArray array = response.getJsonArray("data");
//do stuff with array
}catch(JSONException e){
JSONObject jsonObject = response.getJsonObject("data");
//do stuff with object
}
}else{
//show your error here
}
}
I have a web query with JSON response as:
{
"status":true,
"result":
{
"id":"1",
"name":"ABC 1",
"email":"info#ABc.dcom",
"password":"123456",
"status":false,
"created":"0000-00-00 00:00:00"
},
"message":"Login successfully"
}
I am using the following code for:
#GET("/stockers/login")
public void login(
#Query("email") String email,
#Query("password") String password,
Callback<JSONObject> callback);
In Debugger the query made by the Retrofit library is correct, however I get an empty JSON in response.
ApiManager.getInstance().mUrlManager.login(
email.getText().toString().trim(),
password.getText().toString().trim(),
new Callback<JSONObject>()
{
#Override
public void success(JSONObject jsonObj, Response response)
{
mDialog.dismiss();
Simply use JsonElement insted of JSONobject. Like:
#GET("/stockers/login")
Call<JsonElement> getLogin(
#Query("email") String email,
#Query("password") String password
);
The answers seam kinda old and for Retrofit 1, if you are using Retrofit 2 and don't want to use a converter you have to use ResponseBody.
#GET("/stockers/login")
public void login(
#Query("email") String email,
#Query("password") String password,
Callback<ResponseBody> callback);
And then in your callback in the onResponse method call string on the body and create a JSONObject from it.
if(response.isSuccessful())
JSONObject json = new JSONObject(response.body().string());
Instead of Callback with JSONObject class, you could use the Retrofit basic callback which use the Response class and then, once you get the response, you had to create the JSONObject from it.
See this:
https://stackoverflow.com/a/30870326/2037304
Otherwise you can create your own model class to handle the response.
First the Result class:
public class Result {
public int id;
public String name;
public String email;
public String password;
public boolean status;
public Date created;
}
And then your response class to use with Retrofit
public class MyResponse {
public boolean status;
public Result result;
public String message;
}
Now you can call:
#GET("/stockers/login")
public void login(
#Query("email") String email,
#Query("password") String password,
Callback<MyResponse> callback);
You can create custom factory like belowe or copy it from here :
https://github.com/marcinOz/Retrofit2JSONConverterFactory
public class JSONConverterFactory extends Converter.Factory {
public static JSONConverterFactory create() {
return new JSONConverterFactory();
}
private JSONConverterFactory() {
}
#Override public Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
if (type == JSONObject.class
|| type == JSONArray.class) {
return JSONRequestBodyConverter.INSTANCE;
}
return null;
}
#Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
if (type == JSONObject.class) {
return JSONResponseBodyConverters.JSONObjectResponseBodyConverter.INSTANCE;
}
if (type == JSONArray.class) {
return JSONResponseBodyConverters.JSONArrayResponseBodyConverter.INSTANCE;
}
return null;
}
}
public class JSONRequestBodyConverter<T> implements Converter<T, RequestBody> {
static final JSONRequestBodyConverter<Object> INSTANCE = new JSONRequestBodyConverter<>();
private static final MediaType MEDIA_TYPE = MediaType.parse("text/plain; charset=UTF-8");
private JSONRequestBodyConverter() {
}
#Override public RequestBody convert(T value) throws IOException {
return RequestBody.create(MEDIA_TYPE, String.valueOf(value));
}
}
public class JSONResponseBodyConverters {
private JSONResponseBodyConverters() {}
static final class JSONObjectResponseBodyConverter implements Converter<ResponseBody, JSONObject> {
static final JSONObjectResponseBodyConverter INSTANCE = new JSONObjectResponseBodyConverter();
#Override public JSONObject convert(ResponseBody value) throws IOException {
try {
return new JSONObject(value.string());
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
}
static final class JSONArrayResponseBodyConverter implements Converter<ResponseBody, JSONArray> {
static final JSONArrayResponseBodyConverter INSTANCE = new JSONArrayResponseBodyConverter();
#Override public JSONArray convert(ResponseBody value) throws IOException {
try {
return new JSONArray(value.string());
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
}
}
try this instead :
#GET("/stockers/login")
public void login(
#Query("email") String email,
#Query("password") String password,
Callback<Response> callback); // set the callback generic parameter to Response
ApiManager.getInstance().mUrlManager.login(
email.getText().toString().trim(),
password.getText().toString().trim(),
new Callback<Response>()
{
#Override
public void success(Response response, Response response1)
{
String json = response.getBody();
try {
JSONObject jsonObj = new JSONObject(json);
} catch(JSONException e) {
}
alog.dismiss();
Just define the type of the object you want to get as a String as com.google.gson.JsonObject instead of String and call .toString() on that object to get the JSON string itself.
I`m using this site to create my classes (POJO) from JSON.
http://www.jsonschema2pojo.org/
just be sure to set to JSON insted of JSON Schema and check GSON, because retrofit is using GSON as well for parsing.
your retrofit code looks fine.
Use JacksonConverterFactory instead of GsonConverterFactory while setting up Retrofit. Now you can directly work with JsonObject responses.
compile 'com.squareup.retrofit2:converter-jackson:2.1.0'