Is there any way to Log Gson parsing filed by Field? Log should print name of filed and corresponding value received in response.
Example: Model class looks something like this
public class Item{
#SerializedName("ItemCode")
#Expose
private String ItemCode;
#SerializedName("ItemSN")
#Expose
private String ItemSN;
#SerializedName("ItemDesc")
#Expose
private String ItemDesc;
--getter setter methods--
}
And if response looks as follows:
{
"ItemCode":"A12"
"ItemSN":"123455672"
"ItemDesc":"Google Pixel"
}
At the time of Gson parsing following log should be generated
ItemCode is A12
ItemSN is 123455672
ItemDesc is Google Pixel
I want this to solve following problem. If any other solution works for this kind of problem please suggest.
One API (say init API) for my application returns JSON response which I am parsing using Retrofit-Gson-RxJava, We have two environment setup Test and Prod for prod environment response is getting parsed successfully but for test environment I am getting NumberFormatException which obviously tell us some Numeric filed is having non Numeric value in response.
As the size of response is huge with so many objects nested inside one another hence its getting difficult to find out exact field for which parsing is getting failed.
Add HttpLoggingInterceptor: compile "com.squareup.okhttp3:logging-interceptor:3.3.1"
public static Retrofit getInstance() {
if (instance == null) {
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
httpClient.addInterceptor(logging); // <-- this is the important line!
instance = new Retrofit.Builder().baseUrl(Constant.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(httpClient.build())
.build();
}
return instance;
}
What is this error ? How can I fix this? My app is running but can't load data. And this is my Error: Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 1 path $
This is my fragment :
public class news extends Fragment {
private RecyclerView recyclerView;
private ArrayList<Deatails> data;
private DataAdapter adapter;
private View myFragmentView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
myFragmentView = inflater.inflate(R.layout.news, container, false);
initViews();
return myFragmentView;
}
private void initViews() {
recyclerView = (RecyclerView) myFragmentView.findViewById(R.id.card_recycler_view);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getActivity().getApplicationContext());
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(layoutManager);
data = new ArrayList<Deatails>();
adapter = new DataAdapter(getActivity(), data);
recyclerView.setAdapter(adapter);
new Thread()
{
public void run()
{
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
loadJSON();
}
});
}
}
.start();
}
private void loadJSON() {
if (isNetworkConnected()){
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(interceptor)
.retryOnConnectionFailure(true)
.connectTimeout(15, TimeUnit.SECONDS)
.build();
Gson gson = new GsonBuilder()
.setLenient()
.create();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://www.memaraneha.ir/")
.client(client)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
RequestInterface request = retrofit.create(RequestInterface.class);
Call<JSONResponse> call = request.getJSON();
final ProgressDialog progressDialog = new ProgressDialog(getActivity());
progressDialog.show();
call.enqueue(new Callback<JSONResponse>() {
#Override
public void onResponse(Call<JSONResponse> call, Response<JSONResponse> response) {
progressDialog.dismiss();
JSONResponse jsonResponse = response.body();
data.addAll(Arrays.asList(jsonResponse.getAndroid()));
adapter.notifyDataSetChanged();
}
#Override
public void onFailure(Call<JSONResponse> call, Throwable t) {
progressDialog.dismiss();
Log.d("Error", t.getMessage());
}
});
}
else {
Toast.makeText(getActivity().getApplicationContext(), "Internet is disconnected", Toast.LENGTH_LONG).show();}
}
private boolean isNetworkConnected() {
ConnectivityManager cm = (ConnectivityManager) getActivity().getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo ni = cm.getActiveNetworkInfo();
if (ni == null) {
// There are no active networks.
return false;
} else
return true;
}
}
RequestInterface :
public interface RequestInterface {
#GET("Erfan/news.php")
Call<JSONResponse> getJSON();
}
UPDATE (read below text and find your problem)
most of the time, this error isn't about your json but it could be a
incorrect http request such as a missing or a incorrect header, first check your request with postman to verify the servers response and servers response headers. if nothing is wrong then the error mostly came from your programmed http request, also it could because the servers response is not json (in some cases response could be html).
This is a well-known issue and based on this answer you could add setLenient:
Gson gson = new GsonBuilder()
.setLenient()
.create();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
Now, if you add this to your retrofit, it gives you another error:
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $
This is another well-known error you can find answer here (this error means that your server response is not well-formatted); So change server response to return something:
{
android:[
{ ver:"1.5", name:"Cupcace", api:"Api Level 3" }
...
]
}
For better comprehension, compare your response with Github api.
Suggestion: to find out what's going on with your request/response add HttpLoggingInterceptor in your retrofit.
Based on this answer your ServiceHelper would be:
private ServiceHelper() {
httpClient = new OkHttpClient.Builder();
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
httpClient.interceptors().add(interceptor);
Retrofit retrofit = createAdapter().build();
service = retrofit.create(IService.class);
}
Also don't forget to add:
compile 'com.squareup.okhttp3:logging-interceptor:3.3.1'
Using Moshi:
When building your Retrofit Service add .asLenient() to your MoshiConverterFactory. You don't need a ScalarsConverter. It should look something like this:
return Retrofit.Builder()
.client(okHttpClient)
.baseUrl(ENDPOINT)
.addConverterFactory(MoshiConverterFactory.create().asLenient())
.build()
.create(UserService::class.java)
Also this issue occurres when the response contenttype is not application/json. In my case response contenttype was text/html and i faced this problem. I changed it to application/json then it worked.
There was an error in understanding of return Type
Just add Header and it will solve your problem
#Headers("Content-Type: application/json")
I had same issue along with https://stackoverflow.com/a/57245058/8968137 and both solved after fixing the google-services.json
Im my case I forgot add #Headers("Accept: application/json") to Retrofit and have redirect on http page, with html in body razer json
I have faced this problem and I made research and didn't get anything, so I was trying and finally, I knew the cause of this problem.
the problem on the API, make sure you have a good variable name
I used $start_date and it caused the problem, so I try $startdate and it works!
as well make sure you send all parameter that declare on API, for example,
$startdate = $_POST['startdate'];
$enddate = $_POST['enddate'];
you have to pass this two variable from the retrofit.
as well if you use date on SQL statement, try to put it inside ''
like '2017-07-24'
I hope it helps you.
In my case ; what solved my issue was.....
You may had json like this, the keys without " double quotations....
{ name: "test", phone: "2324234" }
So try any online Json Validator to make sure you have right syntax...
Json Validator Online
I solved this problem very easily after finding out this happens when you aren't outputting a proper JSON object, I simply used the echo json_encode($arrayName); instead of print_r($arrayName); With my php api.
Every programming language or at least most programming languages should have their own version of the json_encode() and json_decode() functions.
This issue started occurring for me all of a sudden, so I was sure, there could be some other reason. On digging deep, it was a simple issue where I used http in the BaseUrl of Retrofit instead of https. So changing it to https solved the issue for me.
Also worth checking is if there are any errors in the return type of your interface methods. I could reproduce this issue by having an unintended return type like Call<Call<ResponseBody>>
Sometimes the error is displayed because the Relative link cannot find the data in the Base URL;
I experienced the same issue and counterchecking that there is no error between the relative URL and base URL worked
I solve this issue after spending around 3 hrs. I have used postman for Api testing.
there was mistake in json output. Please see images for more clarification (I got this error when output preview change from enter image description here JSON to HTML)
I previously implemented the following post request with volley but now i want to use it for retrofit.
So my rest webservice is the following
www.blahblahblah.com/webservice.svc/
I have a function (Person) that is called in the webservice that accepts the following jsonobject
JSONObject jsonObject = new JSONObject();
JSONObject searchCriteria = new JSONObject();
jsonObject.put("FullName", "frank jones");
jsonObject.put("DOB", "06-04-1978");
jsonObject.put("Age", "28");
jsonObject.put("Reason", "Search");
searchCriteria.put("searchCriteria", jsonObject);
So in volley i call www.blahblahblah.com/webservice.svc/Person
and pass the above jsonobject.
Works perfectly
So for Retrofit i've used the same logic, create my jsonobject and pass it in the request
So i use the same url www.blahblahblah.com/webservice.svc/
Create my Post
#POST("Person")
Call<PersonResponseData> getPersonAccess(#Body Object body);
so then my code to get the response
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(urlSearch)
.addConverterFactory(GsonConverterFactory.create())
.build();
RetrofitService service = retrofit.create(RetrofitService.class);
Call<PersonResponseData> personResponseDataCall = service.getPersonAccess(searchCriteria);
personResponseDataCall.enqueue(new Callback<PersonResponseData>() {
#Override
public void onResponse(Response<PersonResponseData> response, Retrofit retrofit) {
int statuscode = response.code();
PersonResponseData personResponseData = response.body();
}
#Override
public void onFailure(Throwable t) {
}
});
I just get a 404 error, any ideas.
As i said this works perfectly in volley but I've done something wrong in retrofit.
Thanks for your help
You can review this question link here is a explanation for use retrofit 2 with POST request
That's only guess, but try following:
1) in Call declaration specify it, not Call getPersonAccess, but Call<PersonResponseData> getPersonAccess;
2) make POJO instead of JSON object and use it as a body instead of passing Object into getPersonAccess call.
I'm using retrofit 2 along with rx java
Situation:
the app sends some request, then i get the response in json-format that is automatically converted to User dto, then in onNext method of rx java i receive the list of Users. What if i get some message from server like this: {"error":"can't get the list of users"}
how to handle this situation with retrofit 2 and rx?
Subscription subscriptionBranches = model.getRepoBranches(owner, name)
.map(branchesMapper)
.subscribe(new Observer<List<Branch>>() {
#Override
public void onCompleted() {
;
}
#Override
public void onError(Throwable e) {
if (e instanceof retrofit.HttpException) {
HttpException exception = (HttpException) e;
}
showError(e);
}
#Override
public void onNext(List<Branch> list) {
branchList = list;
view.showBranches(list);
}
});
addSubscription(subscriptionBranches);
.....
#Override
public Observable<List<RepositoryDTO>> getRepoList(String name) {
return apiInterface
.getRepositories(name)
.compose(applySchedulers());
}
Depending on the server response you might or might not get into your onError function. If the server returns a non-2XX http status code you'll get into the onError method. If on the other hand you get a 2XX http status code you'll enter onNext.
I'm assuming you can deal with the onNext bit and I'll explain how you can do it in the onError. It's important to realise that there are many ways of doing this and this is just an example that uses okhttp 3 and retrofit 2 beta4.
So retrofit2 says that every non-2XX http responses are HttpExceptions when using rxjava. This you already have it there in your code:
if (e instanceof retrofit.HttpException) {
HttpException exception = (HttpException) e;
}
Now what you want to do is get the body of the response. This you can achieve by calling Response response = exception.response() in the HttpException you have there. With the response, getting the error body is quite straight forward. You just call response.errorBody(). You can then convert the body to a java object or just access it as a string.
Since you have a json error body as an example, here's how you can convert the response body to a java object:
new GsonConverterFactory().responseBodyConverter(type,
new Annotation[0]).convert(response.errorBody());
where type is the class of the java object that represents the error.
So putting it all together, on your onError method you could write something like:
if (e instanceof retrofit.HttpException) {
HttpException exception = (HttpException) e;
Response response = exception.response();
Converter<ResponseBody, MyError> converter = new GsonConverterFactory()
.responseBodyConverter(MyError.class, Annotation[0]);
MyError error = converter.convert(response.errorBody());
}
MyError is a model that represents the error json you have in your question.
I believe in the case you mentioned you will just enter into your onError handling, because retrofit will fail to deserialize your response, as it's not formatted as a List. You could potentially handle your case through that based off of the exception type.
If you can't alter the api to return consistent response types, you will have to look into using TypedInput, and possibly a converter.
Additionally, while it may not be completely relevant/overkill to the situation at hand, TypeAdapters bear mentioning. They'll let you determine how retrofit deserializes gson on a per class basis.
Gson gson = new GsonBuilder()
.registerTypeAdapter(MyClass.class, new MyAdapter())
.create();
RestAdapter adapter = new RestAdapter.Builder()
.setConverter(new GsonConverter(gson))
.build();
I had the same situation and the way I could get the json from the server when an error occurs was something like this:
retrofit2.Response<TokenRefresh> r = call.execute();
String errorMessage = "";
try {
errorMessage = r.errorBody().string();
} catch (IOException e) {
e.printStackTrace();
}
Timber.d("errorMessage: " + errorMessage);
When I use OkHttp to post I get a response like this (Instagram api)
{"access_token":"2222222.22222.2222222","user":{"username":"xxx","bio":"","website":"","profile_picture":"https:\/\/instagramimages-a.akamaihd.net\/profiles\/anonymousUser.jpg","full_name":"Test","id":"222222"}}
which I am unable to cast to a JsonObject (I think it is because of the weird way the urls are formatted).
But when I use HttpsUrlConnection everything works fine.
OkHTTP
private final OkHttpClient client = new OkHttpClient();
public static final MediaType MEDIA_TYPE_MARKDOWN
= MediaType.parse("text/plain");
//then in a function
String postBody="client_id="+Application.INSTAGRAM_CLIENT_ID
+"&client_secret="+Application.INSTAGRAM_SECRET_KEY
+"&grant_type=authorization_code"
+"&redirect_uri=" +Application.CALLBACKURL
+"&code=" + SharedPrefHelper.getSharedPerferenceData(context, SharedPrefHelper.SHARED_PREFERENCE_KEY_INSTAGRAM_CODE, "");
Request request = new Request.Builder()
.url(Application.TOKENURL)
.post(RequestBody.create(MEDIA_TYPE_MARKDOWN,postBody))
.build();
I use response.body.string() in the callback method to get the string and cast it to JsonObject.
if (response.code() == 200) {
try {
JSONObject jsonObject = new JSONObject(response.body().string());
} catch (JSONException e) {
}
}
How to fix this ?
ERROR :
org.json.JSONException: End of input at character 0 of
You can only use response.body().string() only once. I was calling it twice. First for logging the response and then again for json casting.
First thing:
You are probably getting a blank response. Its not null but the response is empty. So you are getting this error and not a NullPointerException
Have you logged it before converting in JSON? Checked it.
Second Thing:
You may have to try with GET if you are used POST currently or Vice Versa.