Retrofit 2 error in Json parsing - android

I want to send a post response with no parameters on my url. However the response I am getting is this
[Lcom.example.c4u015.retrotestapp.Questions;#97ddd71
but the actual response is this
{
"MemberDays": "[{"Dt":"02/19/2016","AM":"0","AMS":"1","NS":"0","NSS":"0","PM":"1","PMS":"0","SB":"0","DS":"0","Note":""},{"Dt":"02/25/2016","AM":"0","AMS":"0","NS":"0","NSS":"0","PM":"0","PMS":"0","SB":"0","DS":"0","Note":""}]"
"Message": ""
"Status": "0"
}
This is my code.
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://192.168.1.99:82/MembersWS.svc/")
.addConverterFactory(GsonConverterFactory.create())
.build();
gitAPI stackOverflowAPI = retrofit.create(gitAPI.class);
Call<Questions[]> call = stackOverflowAPI.loadQuestions();
call.enqueue(new Callback<Questions[]>() {
#Override
public void onResponse(Response<Questions[]> response, Retrofit retrofit) {
if (response.isSuccess()) {
Questions[] user = response.body();
Log.e("parsed"," on response");
Log.e("response", response.body().toString()+" "+response.raw().toString());
} else {
int statusCode = response.code();
Log.e("status",""+statusCode);
// handle request errors yourself
ResponseBody errorBody = response.errorBody();
}
pd.dismiss();
}
#Override
public void onFailure(Throwable t) {
pd.dismiss();
Log.e("error", t.getLocalizedMessage());
Toast.makeText(MainActivity.this, t.getLocalizedMessage(), Toast.LENGTH_SHORT).show();
}
});
And this is the interface I have used
public interface gitAPI {
#POST("GetMemberAvailability/MBR0011581")
Call<Questions[]> loadQuestions();
}

you are printing the output of the toString() which is object id in this case, and it's value is waht you see [Lcom.example.c4u015.retrotestapp.Questions;#97ddd71
your response is an Array of type Question, so to print the output you will have to iterate over the array's items and call getters , ex:
user[0].getXXX(); where XXX is any getter method for class Questions
or you can use a for loop or other process you wish

Related

getting null response if email or password is incorrect in retrofit2

i am implementing login web service. i am getting correct response if user email and password is correct. but i am getting null if email or password is incorrect. i want to get message sent from server if email or password is incorrect. My code is below.
Call<LoginResponse> call = RetrofitClient.getInstance().getApi().userLogin(email, password);
call.enqueue(new Callback<LoginResponse>() {
#Override
public void onResponse(Call<LoginResponse> call, Response<LoginResponse> response) {
LoginResponse loginResponse = response.body();
System.out.println("body " + response.body());
System.out.println("response " + response.errorBody().toString());
sharedPrefManager.cancelDialog();
if (loginResponse != null) {
if (loginResponse.getSuccess()) {
sharedPrefManager.saveUser(loginResponse.getData(), password);
Intent intent = new Intent(SignIn.this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
} else {
Toast.makeText(SignIn.this, loginResponse.getMessage(), Toast.LENGTH_SHORT).show();
}
} else {
SharedPrefManager.getInstance(SignIn.this).cancelDialog();
Toast.makeText(SignIn.this, response.message(), Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFailure(Call<LoginResponse> call, Throwable t) {
sharedPrefManager.cancelDialog();
t.printStackTrace();
}
});
public class RetrofitClient {
private static final String BASE_URL = "my_base_url";
private static RetrofitClient mInstance;
private Retrofit retrofit;
OkHttpClient client = new OkHttpClient.Builder()
//.addInterceptor(new SpeechRecognitionIntercepter())
.connectTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS).build();
private RetrofitClient() {
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
public static synchronized RetrofitClient getInstance() {
if (mInstance == null) {
mInstance = new RetrofitClient();
}
return mInstance;
}
public Apis getApi() {
return retrofit.create(Apis.class);
}
}
public interface Apis {
#FormUrlEncoded
#POST("login")
Call<LoginResponse> userLogin(#Field("email") String email, #Field("password") String password);
}
Unsuccessful login response is:
{
"success": false,
"message": "Username or Password is incorrect."
}
Successful response is:
{
"success": true,
"message": "",
"data": {
"token": "",
"name": "Gmail",
"picture": "",
"userid": 60,
"phone": "(111) 114-4444",
"email": "tahir123#gmail.com",
"company_name": null,
"st_address": "Gmail account, Satellite",
"location_id": 1,
"account_type": 2
}
}
It's not really clear from your code if you receive a 200 status even if the call fails, but from what you describe, it seems like you get another http status code.
If this is the case, Retrofit still calls the onResponse method, but response.isSuccessful() is false and the body will be accessible through the response.errorBody() method.
An easy way to get this is:
if(response.isSuccessful())
// Do what you are doing
else {
Gson gson = new Gson();
LoginResponse error = gson.fromJson(response.errorBody().string());
// Use the error variable now
}
There's a lot going on here. Let's start with why do you need manual deserialization. Retrofit doesn't automatically convert the error body for you, you need to do it yourself. Here I've chosen to create a Gson instance, which is not elegant, but serves the purpose.
I also chose to use string(). This method reads the entire response into memory and can crash for big responses. Calling it will drain the okhttp buffer, which means you won't be able to call it again (to the best of my knowledge), so keep it in a variable if you want to use it multiple times.
Hope this helps

Retrofit response showing

I tried to post raw data to server using retrofit method, but I receive the failure response like res fail: Response{protocol=http/1.1, code=500, message=Internal Server Error, url=http://192.168.1.9:8000/api/deviceinfo}
apiService = RetrofitSingleton.createService(ApiService.class);
spyApp = new SpyApp();
Call<ModelResponse> call = apiService.eventsUpdate(jsonObj);
call.enqueue(new Callback<ModelResponse>() {
#Override
public void onResponse(Call<ModelResponse> call, Response<ModelResponse> response) {
Log.e("response", new Gson().toJson(response.body())); //This shows null
if (response.isSuccessful()) {
String status = response.body().getData().getStatus();
} else {
Log.e("res fail", response.toString());
}
}
#Override
public void onFailure(Call<ModelResponse> call, Throwable t) {
Log.e("failure",t.getMessage());
}
});

Retrofit2 NULL response in onResponse even when Data is not NULL

So, my problem is fairly straightforward.
This is the response I am getting through the API call.
D/OkHttp: {"status":"error","status_code":"500","error_msg":"There was an error trying to send the password reset email."}
<-- END HTTP (220-byte body)
This is my code to handle the calls
Call<PasswordReset> forgotPasswordCall = apiInterface.Reset(email);
forgotPasswordCall.enqueue(new Callback<PasswordReset>() {
#Override
public void onResponse(Call<PasswordReset> call, Response<PasswordReset> response) {
PasswordReset passwordReset = response.body();
try {
if (passwordReset.getStatusCode() != null && passwordReset.getStatusCode().equals("200")) { //line 133
Log.d("Success", "Password Reset Email Sent");
new CustomToast().showToast(getContext(), view, "Password Email sent");
new LoginActivity().replaceFragment("left");
} else {
String test = passwordReset.getStatusCode();
Log.d("Failure", test);
hideDialog();
}
}
catch (Exception e){
e.printStackTrace();
hideDialog();
}
}
#Override
public void onFailure(Call<PasswordReset> call, Throwable t) {
Log.d("Failure", "Password Reset Email Not Sent");
new CustomToast().showToast(getContext(), view, "Email Not Sent");
new LoginActivity().replaceFragment("left");
hideDialog();
}
});
And this is the exception I am catching
W/System.err: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String in.siddhant.anetpays_customer.POJO.PasswordReset.getStatusCode()' on a null object reference
at in.siddhant.anetpays_customer.Login.Fragments.ForgotPassword$1.onResponse(ForgotPassword.java:133)
How can my response be null if I am getting some data ?
PasswordReset.class
public class PasswordReset {
#SerializedName("data")
private String data;
#SerializedName("status_code")
private String statusCode;
#SerializedName("status")
private String status;
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public String getStatusCode() {
return statusCode;
}
public void setStatusCode(String statusCode) {
this.statusCode = statusCode;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}
Retrofit Client
public static Retrofit getClient() {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
retrofit = new Retrofit.Builder()
.baseUrl("http://xsdf/")
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
return retrofit;
API_Interface
#FormUrlEncoded
#POST("/ddd/pwdresetrequest")
Call<PasswordReset>Reset(#Field("email")String email);
P.S - The API itself has some problem and always returns "status":"error" but this shouldn't affect the application, right ? Also I am happy to share more code.
Thanks in advance.
Solution
I am posting the solution as suggested as per the accepted answer, Hope it helps someone who comes looking.
forgotPasswordCall.enqueue(new Callback<PasswordReset>() {
#Override
public void onResponse(Call<PasswordReset> call, Response<PasswordReset> response) {
if (!response.isSuccessful()){
Gson gson = new Gson();
PasswordReset passwordReset1 = gson.fromJson(response.errorBody().charStream(), PasswordReset.class);
if (passwordReset1.getStatusCode().equals("500")){
new CustomToast().showToast(getContext(), view, "Password Email not sent");
hideDialog();
}
else {
Thread.dumpStack();
hideDialog();
}
}
else if (response.isSuccessful()) {
Log.d("Success", "Password Reset Email Sent");
new CustomToast().showToast(getContext(), view, "Password Email sent");
new LoginActivity().replaceFragment("left");
}
As for the theory, onResponse method of retrofit2 is called when we get some response and onFailure is called when the process of establishing and receiving a response is not met. I had overlooked this simple fact.
So, if someone does come looking and reading still, I will suggest you to also check your response.body() if its successful or not.
Happy Coding!
From the retrofit's javadoc for Response you can read that body() returns the deserialized response from a successful response. Unfortunately, seems like you have an unsuccessful response, given that you seem to receive a 500.
errorBody() is what you want to use. However, this returns the raw response, so you'll have to deserialize it yourself.
There's a lot of ways you can do this. One might be using gson to deserialize the body:
new Gson().fromJson(response.errorBody().body().string(), YourModel.class);
PS: Just because you end up on onResponse it doesn't mean you have a successful response. However, from your code it seems you already know this and are checking for the http status 200.

Retrofit 2.0 - How to get response body for 400 Bad Request error?

So when I make a POST API call to my server, I get a 400 Bad Request error with JSON response.
{
 "userMessage": "Blah",
"internalMessage": "Bad Request blah blah",
"errorCode": 1
}
I call it by
Call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
//AA
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
//BB
}
}
However the problem is that once I get the response, onFailure() is invoke so that //BB is called. Here, I have no way to access the JSON response.
When I log the api request and response, it doesn't show JSON response at all. And Throwable t is IOException. However, strangely, when I make the same call on Postman, it does return the expected JSON response with 400 error code.
So my question is how can I get the json response when I get 400 Bad Request error? Should I add something to okhttpclient?
Thanks
You can do it in your onResponse method, remember 400 is a response status not an error:
if (response.code() == 400) {
Log.v("Error code 400",response.errorBody().string());
}
And you can handle any response code except 200-300 with Gson like that:
if (response.code() == 400) {
Gson gson = new GsonBuilder().create();
ErrorPojoClass mError=new ErrorPojoClass();
try {
mError= gson.fromJson(response.errorBody().string(),ErrorPojoClass.class);
Toast.makeText(context, mError.getDescription(), Toast.LENGTH_LONG).show();
} catch (IOException e) {
// handle failure to read error
}
}
Add this to your build.gradle : compile 'com.google.code.gson:gson:2.7'
If you want create Pojo class go to Json Schema 2 Pojo and paste your example Json response. Select source type Json and annotation Gson .
You can try the below code to get 400 response. You can get error response from errorBody() method.
Call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
//get success and error response here
if (response.code() == 400) {
if(!response.isSuccessful()) {
JSONObject jsonObject = null;
try {
jsonObject = new JSONObject(response.errorBody().string());
String userMessage = jsonObject.getString("userMessage");
String internalMessage = jsonObject.getString("internalMessage");
String errorCode = jsonObject.getString("errorCode");
} catch (JSONException e) {
e.printStackTrace();
}
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
//get failure response here
}
}
}
EDIT: Fixed method name from toString to string
Handle ErrorResponse with your class object
Kotlin
val errorResponse = Gson().fromJson(response.errorBody()!!.charStream(), ErrorResponse::class.java)
Java
ErrorResponse errorResponse = new Gson().fromJson(response.errorBody.charStream(),ErrorResponse.class)
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
DialogHelper.dismiss();
if (response.isSuccessful()) {
// Success
} else {
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();
}
}
}
First step:
Create your POJO class for error response. In my case, ApiError.java
public class ApiError {
#SerializedName("errorMessage")
#Expose
private String errorMessage;
public String getErrorMessage() {
return errorMessage;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage= errorMessage;
}
}
Second Step:
Write below code in your api callback.
Call.enqueue(new Callback<RegistrationResponse>() {
#Override
public void onResponse(Call<RegistrationResponse> call, Response<RegistrationResponse> response)
{
if (response.isSuccessful()) {
// do your code here
} else if (response.code() == 400) {
Converter<ResponseBody, ApiError> converter =
ApiClient.retrofit.responseBodyConverter(ApiError.class, new Annotation[0]);
ApiError error;
try {
error = converter.convert(response.errorBody());
Log.e("error message", error.getErrorMessage());
Toast.makeText(context, error.getErrorMessage(), Toast.LENGTH_LONG).show();
} catch (IOException e) {
e.printStackTrace();
}
}
}
#Override
public void onFailure(Call<RegistrationResponse> call, Throwable t) {
//do your failure handling code here
}
}
Here ApiClient.retrofit is your retrofit instance which is static.
I got similar issue, but existing code was stick to RxJava 2 chain.
Here's my solution:
public static <T> Observable<T> rxified(final Call<T> request, final Class<T> klazz) {
return Observable.create(new ObservableOnSubscribe<T>() {
AtomicBoolean justDisposed = new AtomicBoolean(false);
#Override
public void subscribe(final ObservableEmitter<T> emitter) throws Exception {
emitter.setDisposable(new Disposable() {
#Override
public void dispose() {
request.cancel();
justDisposed.set(true);
}
#Override
public boolean isDisposed() {
return justDisposed.get();
}
});
if (!emitter.isDisposed())
request.enqueue(new Callback<T>() {
#Override
public void onResponse(Call<T> call, retrofit2.Response<T> response) {
if (!emitter.isDisposed()) {
if (response.isSuccessful()) {
emitter.onNext(response.body());
emitter.onComplete();
} else {
Gson gson = new Gson();
try {
T errorResponse = gson.fromJson(response.errorBody().string(), klazz);
emitter.onNext(errorResponse);
emitter.onComplete();
} catch (IOException e) {
emitter.onError(e);
}
}
}
}
#Override
public void onFailure(Call<T> call, Throwable t) {
if (!emitter.isDisposed()) emitter.onError(t);
}
});
}
});
}
transforming 400-like responses into rx chain is pretty simple:
Call<Cat> request = catApi.getCat();
rxified(request, Cat.class).subscribe( (cat) -> println(cat) );
Here is the simplest solution,
If you want to handle the response from onFailure method:
#Override
public void onFailure(Call<T> call, Throwable t) {
HttpException httpException = (HttpException) t;
String errorBody = httpException.response().errorBody().string();
// use Gson to parse json to your Error handling model class
ErrorResponse errorResponse = Gson().fromJson(errorBody, ErrorResponse.class);
}
Or if you are using rxjava Observable with Kotlin, handle it from error body:
{ error ->
val httpException :HttpException = error as HttpException
val errorBody: String = httpException.response().errorBody()!!.string()
// use Gson to parse json to your Error handling model class
val errorResponse: ErrorResponse =
Gson().fromJson(errorBody, ErrorResponse::class.java)
}
Don't forget to properly handle json to class conversion (use try-catch if not sure).
simply use
if (throwable is HttpException && (throwable!!.code() == 400 || throwable!!.code()==404)){
var responseBody = throwable!!.response()?.errorBody()?.string()
val jsonObject = JSONObject(responseBody!!.trim())
var message = jsonObject.getString("message")
tvValMsg.set(message)
}
This is how you can handle the response message
I am handling for error 500 you can add as much you want
switch (response.code()) {
case HttpURLConnection.HTTP_OK:
break;
case HttpURLConnection.HTTP_UNAUTHORIZED:
callback.onUnAuthentic();
break;
case HttpURLConnection.HTTP_INTERNAL_ERROR:
try {
String errorResponse = response.errorBody().string();
JSONObject object = new JSONObject(errorResponse);
String message = "Error";
if (object.has("Message"))
message = String.valueOf(object.get("Message"));
callback.onError(message);
} catch (IOException e) {
e.printStackTrace();
}
break;
case HttpURLConnection.HTTP_GATEWAY_TIMEOUT:
case HttpURLConnection.HTTP_CLIENT_TIMEOUT:
default:
callback.onNetworkError();
break;
}
IF you are getting 400(Bad Request) by using retrofit first make sure are are setting input to API is Only Model class, If not then replace input request by Model class and then check you will get Success response.
#POST("api/users/CreateAccount")
Call<CreateAccount> createAccount(#Body CreateAccount model, #Header("Content-Type") String content_type);

how to use gson 2.0 on - onResponse from Retrofit 2.0

i'm doing an http call using the new retrofit 2.0,
and getting a callback,
i want to use gson 2.0 library to parse that json obj and to be able to do
jsonData.sector[2].sectorOne
this is my callback:
retrofitApi.Factory.getInstance().getCallData().enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
try {
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.d("myLogs", "failed to Retrive Data");
Log.d("myLogs", "becouse: "+t);
largeTextVar.setText("failed: " + t);
}
});
this is how my callback will look like
{
"data": {
"sector": [
[
{
"scanned": false,
"sectorOne": "",
"sectorTwo": "",
"sectorThree": ""
},
{
"scanned": false,
"sectorOne": "",
"sectorTwo": "",
"sectorThree": ""
}
]
]
},
"curserLocation": {
"elevation": 30,
"horizontal": 105
}
}
i'm using :
compile 'com.squareup.retrofit2:retrofit:2.0.1'
compile 'com.squareup.retrofit2:converter-gson:2.0.1'
i looked everywhere on how to do this, but i couldn't find a simple solution for this,
what is the simplest, easiest way to achieve this ?
Okey i will explain how to convert JSON response to POJO :
First of all you must create a POJO class in : JSON Schema 2 POJO
Paste your example JSON response
Select Source Type : JSON
annotation style : Gson
It will generate a POJO class for you.
Then in your onResponse method :
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if(response.code()==200){
Gson gson = new GsonBuilder().create();
YourPOJOClass yourpojo=new YourPOJOClass ();
try {
yourpojo= gson.fromJson(response.body().toString(),YourPOJOClass.class);
} catch (IOException e) {
// handle failure to read error
Log.v("gson error","error when gson process");
}
}
Dont forget to add compile 'com.google.code.gson:gson:2.4'
Another way to do this : create a pojo class like in above.
In your API :
#POST("endpoint")
public Call<YourPOJOClass> exampleRequest();
When calling this :
OkHttpClient okClient = new OkHttpClient.Builder().connectTimeout(10, TimeUnit.SECONDS).build();
Gson gson = new GsonBuilder()
.setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
.create();
Retrofit client = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create(gson))
.client(okClient)
.build();
YourApiClass service = client.create(YourApiClass.class);
Call<YourPOJOClass> call=service.exampleRequest();
call.enqueue(new Callback<YourPOJOClass>() {
#Override
public void onResponse(Call<YourPOJOClass> call, Response<YourPOJOClass> response) {
//already Gson convertor factory converted your response body to pojo
response.body().getCurserLocation();
}
#Override
public void onFailure(Call<YourPOJOClass> call, Throwable t) {
}
});

Categories

Resources