I am having a issue to get response by using retrofit library.
My JSON is below
{
"regData": [
{
"registrationType": "User",
"userDetails": {
"city": "Bangalore ",
"country": "Bangalore ",
"email": "hfhg#lll.com",
"name": "Cxhcc",
"password": "123456",
"phoneno": "486586"
},
"vehicleRegsiration": {}
}
]
}
Please note that above json i got after debug of my application and when i used same JSON with postman rest client application, it is working fine.
Below is my code
public void postRegistrationData(Registeration reqBody){
ApiInterface apiService = ApiClient.getClient().create(ApiInterface.class);
Call<Long> call = apiService.registrationApi(reqBody);
call.enqueue(new Callback<Long>() {
#Override
public void onResponse(Call<Long> call, Response<Long> response) {
if(response.isSuccessful()){
Long id = response.body().longValue();
Log.d(TAG, "Response: " + id);
} else{
Log.d(TAG, "Response failed: ");
}
}
#Override
public void onFailure(Call<Long>call, Throwable t) {
Log.e(TAG, t.toString());
}
});
}
After execution of above code its always executing below code
Log.d(TAG, "Response failed: ");
public Registeration prepareRegRequestBody(UserDetails uDetail , VehicleRegsiration vDedail, String regType){
RegDatum reg = new RegDatum();
List<RegDatum> regList = new ArrayList<RegDatum>();
Registeration regUV = new Registeration();
reg.setRegistrationType(regType);
reg.setUserDetails(uDetail);
reg.setVehicleRegsiration(vDedail);
regList.add(reg);
regUV.setRegData(regList);
return regUV;
}
public Registeration inputDataUV(){
UserDetails userDetail = new UserDetails();
VehicleRegsiration vehicleRegsiration = new VehicleRegsiration();
Registeration reqbody = new Registeration();
if(userType.getSelectedItem().toString().equalsIgnoreCase("User")){
userDetail.setEmail(signupInputEmail.getText().toString());
userDetail.setPassword(signupInputPassword.getText().toString());
userDetail.setPhoneno(signupInputMobile.getText().toString());
userDetail.setName(signupInputName.getText().toString());
userDetail.setCountry(countryName1.getText().toString());
userDetail.setCity(signupInputCity.getText().toString());
reqbody = prepareRegRequestBody(userDetail, vehicleRegsiration, "User" );
return reqbody;
} else if(userType.getSelectedItem().toString().equalsIgnoreCase("Vehicle")){
vehicleRegsiration.setVehicleOwner(vSignupEmailId.getText().toString());
vehicleRegsiration.setVehicleNoPlate(vSignupVnumber.getText().toString());
vehicleRegsiration.setVehicleType(vSignupType.getText().toString());
vehicleRegsiration.setImeiNo(Long.parseLong(vSignupImeiNo.getText().toString()));
vehicleRegsiration.setPassword(vSignupPassword.getText().toString());
vehicleRegsiration.setCountry(vcountryName1.getText().toString());
vehicleRegsiration.setCity(vSignupCity.getText().toString());
reqbody = prepareRegRequestBody(userDetail, vehicleRegsiration, "Vehicle" );
return reqbody;
} else{
return reqbody;
}
}
Where i am doing wrong please help me get rid of this issue.
Related
Here is my GSON response and my response is dynamic.
Note: I can't change response
{ "soapBody": {
"GenerateProposalResponse": {
"GenerateProposalResult": {
"POL_SYS_ID": "102123205",
"PROPOSAL_NO": "10083\/31\/20\/P\/0004354",
"VehicleIDV": {
},
"ERROR_DESC": "Proposal created successfully......!",
"ERROR_CODE": "0",
"CoverDtlList": {
"CoverDtl": [
{
"CoverDesc": "BASIC TP COVER",
"Premium": "752",
"Type": {
}
},
{
"CoverDesc": "GR36A-PA FOR OWNER DRIVER",
"Premium": "315",
"Type": "ADD"
},
{
"CoverDesc": "TP TOTAL",
"Premium": "1067",
"Type": {
}
},
{
"CoverDesc": "TOTAL PREMIUM",
"Premium": "1067",
"Type": {
}
},
{
"CoverDesc": "IGST",
"Premium": "192",
"Type": "ADD"
},
{
"CoverDesc": "TOTAL AMOUNT",
"Premium": "1259",
"Type": {
}
}
]
}
}
} } }
many time, I got "VehicleIDV": "1230" and many time I got "VehicleIDV":{}
W/System.err: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected a string but was BEGIN_OBJECT at line 1 column 149 path $.soapBody.GenerateProposalResponse.GenerateProposalResult.VehicleIDV
Here is my function
public void getShri(final Context mContext, String id) {
ApiClient restClient = new ApiClient(mContext);
restClient.setCommunication();
ApiInterface apiService = restClient.getApiService();
try {
Call call = apiService.getShri(id);
call.enqueue(new Callback<Shri>() {
#Override
public void onResponse(Call<Shri> call, Response<Shri> response) {
if (response.isSuccessful()) {
Shri commonResponse = response.body();
((onRequestCompleteCallBackListener) mContext).
onResponse(commonResponse);
}
}
#Override
public void onFailure(Call<Shri> call, Throwable t) {
//onResponse(t);
t.printStackTrace();
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
and here is apiInterface code
#FormUrlEncoded
#POST("shri.php")
Call<Shri> getShri(#Field("id") String id);
im doing a test using retrofit and a mock api, i have already a recyclerview with a list of products and the detail of the product while clicking on the row, but in some products the josn is a error handling example :
http://mocklab.io/product/1/
{
"success": true,
"metadata": {
"sku": "2",
"name": "Huawei P20 Pro",
"max_saving_percentage": 30,
"price": 13996,
"special_price": 7990,
"brand": "Huawei",
"rating": {
"average": 4,
"ratings_total": 265
},
but lets say in my case product "3" give me the error json :
http:mocklab.io/product/3/
{
"success": false,
"messages": {
"error": {
"reason": "PRODUCT_NOT_FOUND",
"message": "Product not found!"
}
}
}
the pojos are already done with jsonschema2pojo, so the question is if i click in the 3 row in the recyclerview my app crash because and i get null object reference, but what i want is to hadle the error they ask that is : HTTP 200 - Success false , sorry if i didnt explain myself the best way, and thank you!
call:
GetPhoneDataService service = RetrofitInstance.getRetrofitInstance().create(GetPhoneDataService.class);
Call<APIReponse> call = service.getAllPhones(1);
call.enqueue(new Callback<APIReponse>() {
#Override
public void onResponse(Call<APIReponse> call, Response<APIReponse> response) {
if (response.isSuccessful() && response.body() != null) {
for (Result result : response.body().getMdata().getResults()) {
phoneList.add(result);
}
adapter.setOnClickListener(new PhonesAdapter.OnItemClickListener() {
#Override
public void onItemClick(int position) {
String sku = phoneList.get(position).getSku();
Intent intent = new Intent(MainActivity.this, DetailsActivity.class);
intent.putExtra("sku", sku);
startActivity(intent);
}
});
adapter.notifyDataSetChanged();
} else {
try {
String error = response.errorBody().string();
if (error != null) {
Log.e("Error : ", error);
}
//show error to the user
} catch (Exception e) {
e.printStackTrace();
}
In Retrofit you can handle errors response like this. Inside onResponse callback:
if (response.isSuccessful()
&& response.body() != null) {
//Call was successful and body has data
} else {
try {
String error = response.errorBody().string();
if(error != null)
//show error to the user
} catch (Exception e) {
e.printStackTrace();
}
}
But if your error is thrown here:
public void onItemClick(int position) {
String sku = phonesList.get(position).getSku();
Log.e("ffff", "----- " + sku);
Intent intent = new Intent(MainActivity.this,DetailsActivity.class);
intent.putExtra("sku", sku);
startActivity(intent);
}
then you have problems with not designing your code very well. I don't know context of your code more precisely context when you call generatePhonesList method but, if you need to call it more then once, then consider not setting adapter and recyclerview inside that method. For that you have something called: notifyDataSetChanged()
I'm trying to do an application that display some article stored in a SQLite database.
I use a php function on my server to get a JSON file containing my database. In my Android app I want to get that JSON and put it in a JSONObject, I did the following :
private void initDataset() {
mDataset = new ArrayList<>();
Log.d("InitDataset", String.valueOf(mDataset.size()));
getArticles();
Log.d("InitDataset", String.valueOf(mDataset.size()));
}
public void getResponse(int method, String url, JSONObject jsonValue, final VolleyCallback callback) {
StringRequest strreq = new StringRequest(method, url, new Response.Listener < String > () {
#Override
public void onResponse(String Response) {
callback.onSuccessResponse(Response);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError e) {
e.printStackTrace();
Toast.makeText(getContext(), e + "error", Toast.LENGTH_LONG).show();
}
});
AppController.getInstance().addToRequestQueue(strreq);
}
public void getArticles() {
getResponse(Request.Method.GET, AppConfig.URL_ARTICLE, null,
new VolleyCallback() {
#Override
public void onSuccessResponse(String result) {
for (int i = 1; i < 3; i++) {
try {
Article article = new Article();
JSONObject response = new JSONObject(result);
// Now store the articles in SQLite
JSONObject articleObj = response.getJSONObject("article" + i);
article.setArticle_id(i);
article.setPicture_url(articleObj.getString("picture_url"));
article.setName(articleObj.getString("name"));
article.setDescription(articleObj.getString("description"));
article.setQuantity(Float.parseFloat(articleObj.getString("quantity")));
article.setPrice(Float.parseFloat(articleObj.getString("price")));
mDataset.add(article);
} catch (JSONException e) {
e.printStackTrace();
}
}
}
});
}
public interface VolleyCallback {
void onSuccessResponse(String result);
}
But in the Log, the size of mDataset is always 0. Or if I Log for example the name of the article in onResponse() I can see every name is in the database. (thus the connection and php function are alright I think)
Any idea ?
Here is the php file :
<?php
require_once 'include/DB_Functions.php';
$db = new DB_Functions();
// JSON response array
$response = array("error" => FALSE);
$article = $db->getAllArticles();
if ($article != false) {
// use is found
$response["error"] = FALSE;
while($row = $article->fetch_assoc()) {
$response["article".$row["article_id"]]["article_id"] = $row["article_id"];
$response["article".$row["article_id"]]["picture_url"] = $row["picture_url"];
$response["article".$row["article_id"]]["name"] = $row["name"];
$response["article".$row["article_id"]]["description"] = $row["description"];
$response["article".$row["article_id"]]["quantity"] = $row["quantity"];
$response["article".$row["article_id"]]["price"] = $row["price"];
}
echo json_encode($response);
$fp = fopen('results.json', 'w');
fwrite($fp, json_encode($response));
fclose($fp);
} else {
$response["error"] = TRUE;
$response["error_msg"] = "Error";
echo json_encode($response);
}
?>
And the JSON I get when executing the php :
{
"error": false,
"article1": {
"article_id": "1",
"picture_url": "https://static.webshopapp.com/shops/019852/files/024106649/600x600x2/brasserie-dachouffe-la-chouffe-33cl.jpg",
"name": "Chouffe",
"description": "Ceci est une description de la chouffe.",
"quantity": "33",
"price": "2.54"
},
"article2": {
"article_id": "2",
"picture_url": "https://www.latelierdesbieres.fr/1266-large_default/biere-belge-noel-n-ice-chouffe-33-cl.jpg",
"name": "Chouffe de Noel",
"description": "Ceci est une description de la chouffe de Noel.",
"quantity": "33",
"price": "3.23"
}
}
You're misunderstanding some asynchronous execution ordering.
You need to rewrite your method to wait for the returned results, not immediately log the list size twice without letting the network call finish
getArticles(new VolleyCallback() {
#Override
public void onSuccessResponse(String result) {
// parse result
// print list size <-- shouldn't be empty
}
});
// your list will be empty here still
Where the method is defined as
public void getArticles(VolleyCallback vcb) {
getResponse(Request.Method.GET, AppConfig.URL_ARTICLE, null, vcb);
}
However, that seems really pointless to wrap two methods when you could just call getResponse directly with the correct parameters
How to handle error response with Retrofit 2 using synchronous request?
I need process response that in normal case return pets array and if request has bad parametrs return error json object. How can I process this two situations?
I am trying to use this tutorial but the main problem is mapping normal and error json to objects.
My normal response example:
[ {
"type" : "cat",
"color": "black"
},
{
"type" : "cat",
"color": "white"
} ]
Error response example:
{"error" = "-1", error_description = "Low version"}
What I got:
Call<List<Pet>> call = getApiService().getPet(1);
Response<List<Pet>> response;
List<Pet> result = null;
try {
response = call.execute(); //line with exception "Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path"
if(!response.isSuccessful()){
Error error = parseError(response);
Log.d("error message", error.getErrorDescription());
}
if (response.code() == 200) {
result = response.body();
}
} catch (IOException e) {
e.printStackTrace();
}
Retrofit 2 has a different concept of handling "successful" requests than Retrofit 1. In Retrofit 2, all requests that can be executed (sent to the API) and for which you’re receiving a response are seen as "successful". That means, for these requests, the onResponse callback is fired and you need to manually check whether the request is actually successful (status 200-299) or erroneous (status 400-599).
If the request finished successfully, we can use the response object and do whatever we wanted. In case the error actually failed (remember, status 400-599), we want to show the user appropriate information about the issue.
For more details refer this link
After going through a number of solutions. Am posting it for more dynamic use. Hope this will help you guys.
My Error Response
{
"severity": 0,
"errorMessage": "Incorrect Credentials (Login ID or Passowrd)"
}
Below is as usual call method
private void makeLoginCall() {
loginCall = RetrofitSingleton.getAPI().sendLogin(loginjsonObject);
loginCall.enqueue(new Callback<Login>() {
#Override
public void onResponse(Call<Login> call, Response<Login> response) {
if (response != null && response.code() == 200){
//Success handling
}
else if (!response.isSuccessful()){
mServerResponseCode = response.code();
Util.Logd("In catch of login else " + response.message());
/*
* Below line send respnse to Util class which return a specific error string
* this error string is then sent back to main activity(Class responsible for fundtionality)
* */
mServerMessage = Util.parseError(response) ;
mLoginWebMutableData.postValue(null);
loginCall = null;
}
}
#Override
public void onFailure(Call<Login> call, Throwable t) {
Util.Logd("In catch of login " + t.getMessage());
mLoginWebMutableData.postValue(null);
mServerMessage = t.getMessage();
loginCall = null;
}
});
}
Below Is util class to handle parsing
public static String parseError(Response<?> response){
String errorMsg = null;
try {
JSONObject jObjError = new JSONObject(response.errorBody().string());
errorMsg = jObjError.getString("errorMessage");
Util.Logd(jObjError.getString("errorMessage"));
return errorMsg ;
} catch (Exception e) {
Util.Logd(e.getMessage());
}
return errorMsg;
}
Below in viewModel observer
private void observeLogin() {
loginViewModel.getmLoginVModelMutableData().observe(this, login -> {
if (loginViewModel.getSerResponseCode() != null) {
if (loginViewModel.getSerResponseCode().equals(Constants.OK)) {
if (login != null) {
//Your logic here
}
}
//getting parsed response message from client to handling class
else {
Util.stopProgress(this);
Snackbar snackbar = Snackbar.make(view, loginViewModel.getmServerVModelMessage(), BaseTransientBottomBar.LENGTH_INDEFINITE).setAction(android.R.string.ok, v -> { });
snackbar.show();
}
} else {
Util.stopProgress(this);
Snackbar snackbar = Snackbar.make(view, "Some Unknown Error occured", BaseTransientBottomBar.LENGTH_INDEFINITE).setAction(android.R.string.ok, v -> { });
snackbar.show();
}
});
}
I think you should create a generic response class (let's say GenericResponse), that is extended by a specific response class (let's say PetResponse). In the first one, you include generic attributes (error, error_description), and in the latter, you put your specific response data (List<Pet>).
In your case, I would go with something like this:
class GenericResponse {
int error;
String error_description;
}
class PetResponse extends GenericResponse {
List<Pet> data;
}
So, your successful response body should look like this:
{
"data": [ {
"type" : "cat",
"color": "black"
},
{
"type" : "cat",
"color": "white"
} ]
}
And your error response body should look like this:
{ "error" = "-1", error_description = "Low version"}
Finally, your response object that is returned from the API call should be:
Response<PetResponse> response;
Wrap all your calls in retrofit2.Response like so:
#POST("user/login")
suspend fun login(#Body form: Login): Response<LoginResponse>
A very simple retrofit 2 error handler:
fun <T> retrofitErrorHandler(res: Response<T>): T {
if (res.isSuccessful) {
return res.body()!!
} else {
val errMsg = res.errorBody()?.string()?.let {
JSONObject(it).getString("error") // or whatever your message is
} ?: run {
res.code().toString()
}
throw Exception(errMsg)
}
}
Then use them like:
try {
createdReport = retrofitErrorHandler(api...)
} catch (e: Exception) {
toastException(ctx = ctx, error = e)
}
I'm trying to parse the following JSON structure using Retrofit on android.
{
"payload": [
{
"name": "Rice",
"brands": [
{
"name": "Dawat",
"subProducts": [
{
"id": 1,
"name": "Basmati Long Grain",
"creditDays": 20,
"currency": "$",
"willDeliver": false,
"minPrice": 250,
"maxPrice": 400,
"sku": "1Kg",
"uom": ""
}
]
}
]
}
],
"messages": []
}
I have made models using http://www.jsonschema2pojo.org/. The keys I'm particularly are payload-->name, brands-->name and subProducts-->name. Below is what I've tried so far. Can anyone please help? I can't parse this JSON Structure using retrofit
productDetails.enqueue(new Callback<GetProductDetailsByPhoneNumber>() {
#Override
public void onResponse(Call<GetProductDetailsByPhoneNumber> call, Response<GetProductDetailsByPhoneNumber> response) {
Toast.makeText(getApplicationContext(), "Response mil gaya", Toast.LENGTH_LONG);
List<Payload> subProducts = new ArrayList<Payload>(response.body().payload);
}
#Override
public void onFailure(Call<GetProductDetailsByPhoneNumber> call, Throwable t) {
}
});
Interface:
#GET("wholesaler/getProductDetailsByPhoneNumber")
Call<GetProductDetailsByPhoneNumber> getProducts(#Query("phoneNumber") String number);
getDService()
public API getDService(){
/**
* The Retrofit class generates an implementation of the API interface.
*/
if(service == null){
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Constants.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
service = retrofit.create(API.class);
}
return service;
}
Payload.java
public class Payload {
public String name;
public List<Brand> brands;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Brand> getBrands() {
return brands;
}
public void setBrands(List<Brand> brands) {
this.brands = brands;
}
}
Try using this, as you are not providing your "Payload"o bject
productDetails.enqueue(new Callback<JsonObject>() {
#Override
public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
if(response.body()!=null{
JsonObject jsonObject=response.body();
if(response.code() == 200){
if(jsonObject.has("payload"){
JsonArray dataArray = jsonObject.getAsJsonArray(HAS_DATA);
if (dataArray.size() > 0) {
Toast.makeText(getApplicationContext(), "Response Called", Toast.LENGTH_LONG);
//your further code
}
}
}
}
}
#Override
public void onFailure(Call<JsonObject> call, Throwable t) {
//logic for if response fails
}
});
Use this code in your onResponse:
if(response.code()==HttpsURLConnection.HTTP_OK) { //HttpOk is the response code for 200
if (response.body() != null) {
if (response.body().payload!= null) {
//data is there in an array of type payload
//save all the data there
//like you want the name, you can get that by response.body().payload.name and you will get "rice"
//similarly if you want the name which is in subproducts array use : response.body().payload.get(0).brands.get(0).subProducts.get(0).name and you
// will get "Basmati Long Grain"
}
}
}
The code will help you deserialise all the data from the JSON and you can store that wherever you want. Plus I will recommend you to keep a check on other response codes as well(such as 400 for bad request, 500 for internal server error etc). See here, you have your payload in an array, and there was only one element in it, that is why I have used payload.get(0). In case of multiple elements in the array you need to use a loop and then fetch the values, same goes for your brands and subProduct array.
You are trying to get an object PayLoad, and you have
{
"payload": [
{
"name"
this means it doesn't start with a parent, so you need to save the answer in a List like List and letter in the iteration you can use Response.get(position) <-- and this one going to be your payload number position, I hope this can help you