Expected JsonObject but was JsonPrimitive - android

I am using retrofit to parse JSON. I'm getting an exception while parsing a JSON response. My response is dynamic means that when I'm getting a successful response the response key is successful, but when I'm getting a fail response it turns to an error. How can I parse that response?
When I'm getting a fail response it's giving me a proper result, but when I'm getting a successful response it's going to end in failure and gives me an exception that Expected JsonObject but was JsonPrimitive.

I had a similar problem where server returned sometimes a JsonObject and sometimes a JsonPrimitive. When JsonPrimitive was returned I got 200 OK but it still ends up in onFailure because the types differed ( It expected a JsonObject but found a JsonPrimitive ).
public final class JsonPrimitive extends JsonElement
public final class JsonObject extends JsonElement
The com.google.gson documentation states that booth JsonPrimitive and JsonObject extend JsonElement so why not do:
JsonObject jsonObject = createJsonObject();
Call<JsonElement> requestCall = SomeInterface.sendRequest(jsonObject);
requestCall.enqueue(new Callback<JsonElement>() {
#Override
public void onResponse(Call<JsonElement> call, Response<JsonElement> response) {
//Now when you get a JsonPrimitive it will still end up here because
//JsonPrimitive extends JsonElement
}
#Override
public void onFailure(Call<JsonElement> call, Throwable t) {
}
}

Jsonobject and jsonprimitive is different type each other .
JsonObject { "name":"John", "age":30, "car":null }
JsonPrimitive (string, number, boolean)
Your response model is wrong . try this .
http://www.jsonschema2pojo.org/

Your API response is String and you try to get JsonObject.
check your API in Postman and sure API response is JsonObject.

Related

Using Volley without Gson

Today I got to know that Retrofit uses gson(or any other convertor) to serialize or deserialize the json response (response that was got using okhttp or any related library).
Now, when I was naive(in some sense still am) and I used to use Volley and at that time I never used Gson or any related library and same for okhttp.But i used to get my response and inflate it successfully on my views.
1. Now does Volley internally do what Retrofit does using Gson and Okhttp?
If not? 2. Then how did i able to get values parsed without using anything?
Below is the sample Codes that i used to write:-
JsonObjectRequest jsonObjectRequest=new JsonObjectRequest(
Request.Method.POST, URL_THUMB, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
JSONArray jsonArray=response.getJSONArray("server_response");
for(int i=0;i<jsonArray.length();i++)
{
JSONObject jsonObject=(JSONObject)jsonArray.get(i);
String id=jsonObject.getString("id");
String artist_name=jsonObject.getString("artist_name");
String img_id=jsonObject.getString("img_id");
listId.add(id);
listArtistName.add(artist_name);
listImgID.add(img_id);
}
recyclerView.setAdapter(comedy_adapter);
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
}
);
and now just inflate these list values to my views.
Where did I go wrong? (I don't think I was wrong as things went well and code always run fine)
In your example you're parsing the response into JSON arrays and objects manually. Converters such as Gson let you parse the response into a variable of a custom object in a single line.
For example, if I have the following model:
public class Model {
private int id;
private String name;
}
I can parse a string response using the following code:
Model model = gson.fromJson(str, Model.class);
Otherwise, you have to do it manually, like what you're doing at the moment:
JSONObject jsonObject = response.getJSONObject("str");
int id = jsonObject.getInt("id");
String name = jsonObject.getString("name");
Model model = new Model(id, name);
In Retrofit 2 you don't even have to call fromJson - you simple receive the object you expect as an input parameter in onResponse. It's very useful when dealing with more complex models.

How to parse JSON array with single element without any object in Retrofit?

I am using Retrofit which uses GSON for parsing.The server will check the parameter i am sending and returns two responses Accordingly.
If the parameter is valid i am getting the following response
[
true
]
If it is not valid then i get response as,
[
"Sorry, <em class=\"placeholder\">names#gmail.inp</em> is not recognized as a user name or an e-mail address."
]
This is the call method i am using.
#Override
public void onResponse(Call<String> call, Response<String> response) {
mProgressBar.setVisibility(View.GONE);
Log.d("Response ", ""+response);
}
here response.body giving me as null. But there is a response.which is viewable in OKHttp Log.
you can try this
JSONArray jArray=new JSONArray(yourString);
String str=jArray.getString(0);;
if(str.equalsIgnoreCase("true")
{
//your code
}else
{
}
JSONArray jarray = new JSONObject(jsonString);
for (int i = 0; i < jarray.length(); i++) {
String string = jarray.getString(i);
log.e("String",string);
}
that's working great. Please try this.
You can use JsonParser provided by Gson. It will parse the json input to dynamic JsonElement.
Look at MByD example:
public String parse(String jsonLine) {
JsonElement jelement = new JsonParser().parse(jsonLine);
JsonObject jobject = jelement.getAsJsonObject();
jobject = jobject.getAsJsonObject("data");
JsonArray jarray = jobject.getAsJsonArray("translations");
jobject = jarray.get(0).getAsJsonObject();
String result = jobject.get("translatedText").toString();
return result;
}
since the server return diffrent codes
can you try
Call<Void>
and check the response code
this might work for now until you know what is wrong void will not parse any thing so it shouldn't cause a crash
///////
did you try
Call<ArrayList<String>>
also are you sure the server returns 200 in both cases ?

Unable to get json string as response in Retrofit 2.0 android

This is not a duplicate question.
I am using Retrofit 2.0 and json for network tasks.
Also I am not using GSON to parse json instead I am using simple JsonObject and JsonArray to get model objects from json string.
Firstly guide me which retrofit converter must be used for above scenario.
Secondly, I am not able to get json string as response string.
I tried two approaches -
Approach 1 - I used Call< Void >. In this case the response.body() returns null though status code is 200.
Approach 2 - I used Call< ResponseBody >. In this case call.enqueue methods call 'on failure method' instead of 'onSuccess' and also the response body is null.
The status code is 200 in this case also.
Please suggest how to get the json string as response from retrofit 2.0.
you need to use JsonObject instead of Void or ResponseBody. Your code should be
Call<JsonObject> getCall = request.getDataCall();
getCall.enqueue(new Callback<JsonObject>() {
#Override
public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
}
#Override
public void onFailure(Call<JsonObject> call, Throwable t) {
}
});
Note : make sure you are using com.google.gson.JsonObject

How can I delete the nameValuePairs key from the JSONObject?

I'm working on an Android project which needs a JSONObject for the body of my POST request.
After putting the keys and values of the JSON I got the following line:
{
"xxxx":"zzzzzzz",
"yyyy":"uuuuuuu"
}
But the server got the following:
{
"name_value_pairs": {
"xxxx":"zzzzzzz",
"yyyy":"uuuuuuu"
}
}
I've already tried a JSONStringer but it wasn't really helpful because the Content-Type of the request is application/json.
UPDATE
I'm not trying to construct a JSONObject because it's already done by using the following line of code (the same given by #osayilgan):
JSONObject jsonRequest = new JSONObject();
jsonRequest.put("xxxx", "zzzzzzz");
jsonRequest.put("yyyy", "uuuuuuu");
Here is not the problem. The interface described below is used to communicate with the server.
public interface MyService {
#Headers({"Content-type: application/json",
"Accept: */*"})
#POST("/test")
void testFunction(#Body JSONObject jsonObject, Callback<Response> callback);
}
The server got the request with the second JSON as Body which is disappointing. I note that the key name_value_pairs is automatically added to the object.
Does anybody know how can I fix this?
Issue:
Retrofit by default uses GSON to convert HTTP bodies to and from JSON. The object which is specified with #Body annotation will be passed to GSON for serialization, which basically converts the JAVA object to JSON representation. This JSON representation will be the HTTP request body.
JSONObject stores all the key-value mapping in a member variable by name nameValuePairs.
Here is an excerpt of JSONObject implementation:
public class JSONObject {
...
private final Map<String, Object> nameValuePairs;
...
}
When you pass JSONObject to #Body annotation, this JSONObject is seraliazed, hence the HTTP request body contains : {"nameValuePairs": "actual JSON Object"}.
Solution:
Pass the actual JAVA object to #Body annotation, not it's corresponding JSONObject. GSON will take care of converting it to JSON representation.
For e.g.
class HTTPRequestBody {
String key1 = "value1";
String key2 = "value2";
...
}
// GSON will serialize it as {"key1": "value1", "key2": "value2"},
// which will be become HTTP request body.
public interface MyService {
#Headers({"Content-type: application/json",
"Accept: */*"})
#POST("/test")
void postJson(#Body HTTPRequestBody body, Callback<Response> callback);
}
// Usage
MyService myService = restAdapter.create(MyService.class);
myService.postJson(new HTTPRequestBody(), callback);
Alternative solution:
If you still want to send raw JSON as HTTP request body, then follow the solution mentioned by Retrofit author here.
One of the suggested solution is to use TypedInput:
public interface MyService {
#POST("/test")
void postRawJson(#Body TypedInput body, Callback<Response> callback);
}
String json = jsonRequest.toString();
TypedInput in = new TypedByteArray("application/json", json.getBytes("UTF-8"));
myService.postRawJson(in, callback);
Use com.google.gson.JsonObject instead of org.json.JSONObject.
JSONObject jsonRequest = new JSONObject();
jsonRequest.put("xxxx", "zzzzzzz");
jsonRequest.put("yyyy", "uuuuuuu");
Change to
JsonObject jsonRequest = new JsonObject();
jsonRequest.addProperty("xxxx", "zzzzzzz");
jsonRequest.addProperty("yyyy", "uuuuuuu");
Then in interface
public interface MyService {
#Headers({"Content-type: application/json",
"Accept: */*"})
#POST("/test")
void testFunction(#Body JsonObject jsonObject, Callback<Response> callback);
}
JSONObject class keeping the values in LinkedHashMap with the variable name of nameValuePairs, When Gson trying to convert the JSONObject's instance into JSON,
GSON keeps the structure(which has the variable nameValuePairs). That causing this problem.
you have to covert JSONObject to JsonObject of GSON
follow this way
JsonParser jsonParser = new JsonParser();
JsonObject jsonObject = (JsonObject)jsonParser.parse(actualjsonobject.toString());
then pass in body
HashMap<String,Object> body=new HashMap();
body.put("content",jsonObject);
Thanks to 13KZ, pointed me in the right direction, and to flesh it out here is what I now have to solve this issue.
Definitions
private JsonObject gsonResultTwoWeek;
private JsonObject gsonResultDay;
private JsonObject gsonResult;
Initialise
gsonResult = new JsonObject();
gsonResultDay = new JsonObject();
gsonResultTwoWeek = new JsonObject();
Use
gsonResultDay.addProperty(epoch, value);
where data is a string and value is an int in my case and is in a for loop to add multiple values
And then to pull it all together
gsonResult.addProperty("accounts", 2);
gsonResult.add("todaydata", gsonResultDay);
gsonResult.add("2weekdata", gsonResultTwoWeek);
Finally my interface
public interface ApiInterface {
#POST("/groupdata")
void postGroupData(#Body JsonObject body,Callback<StatusResponse> cb);
}
What hits my server is this
{"accounts":2,"todaydata":{"1423814400":89,"1423816200":150,"1423818000":441},"2weekdata":{"1423699200":4869,"1423785600":1011}}
My solution is based on 13KZ's
public class MyRequest {
#SerializedName(Constants.ID)
private String myID;
#SerializedName(Constants.PARAM_ANSWERS)
private JsonObject answers;
public MyRequest(String id, Hasmap<String, String> answers) {
this.myID = id;
this.answers = new JsonObject();
for (String s: answers.keySet()) {
this.answers.addProperty(s, answers.get(s));
}
}
}
JSONObject jsonRequest = new JSONObject();
try {
jsonRequest.put("abc", "test");
jsonRequest.put("cba", "tye");
} catch (JSONException e) {
e.printStackTrace();
}
Log.d("jsonobject", "onClick: "+jsonRequest);
(result: {"abc":"test","cba":"tye"})
JsonParser jsonParser = new JsonParser();
JsonObject jsonObject = (JsonObject)jsonParser.parse(jsonRequest.toString());
Log.d("jsonobjectparse", "onClick: "+jsonObject);
(result: {"abc":"test","cba":"tye"})
Once you are put the values into the jsonObject pass to the jsonParser it will solve the issue
thats all. enjoy your coding.
nameValuePairs in retfrofit error
get this type
{
"nameValuePairs": {
"email": "mailto:test1#gmail.com",
"password": "12345678"
}
}
need this type
{
"email": "mailto:test1#gmail.com",
"password": "12345678"
}
#POST("login")
suspend fun getLogin(#Body jsonObject: RequestBody) : Response<LoginModel>
In Repository Class
Add this line for conver in json utf-8 fomat
val body = jsonObject.toString().toRequestBody("application/json; charset=utf-8".toMediaTypeOrNull())
class LoginRepository constructor(private val retrofitService: RetrofitService) {
suspend fun getLogin(jsonObject: JSONObject): NetworkState<LoginModel> {
val body = jsonObject.toString().toRequestBody("application/json; charset=utf-8".toMediaTypeOrNull())
val response = retrofitService.getLogin(body)
return if (response.isSuccessful) {
val responseBody = response.body()
if (responseBody != null) {
NetworkState.Success(responseBody)
} else {
NetworkState.Error(response)
}
} else {
NetworkState.Error(response)
}
}
}
It appears that you are attempting to transmit the actual JSONObject rather the the JSON text-string representation of the object. A look at the specification for the JSONObject class shows that you should be using the .toString() method to get the JSON text representation of the data structure kept by the JSONObject. Thus, you should be able to change:
public interface MyService {
#Headers({"Content-type: application/json",
"Accept: */*"})
#POST("/test")
void testFunction(#Body JSONObject jsonObject, Callback<Response> callback);
}
to:
public interface MyService {
#Headers({"Content-type: application/json",
"Accept: */*"})
#POST("/test")
void testFunction(#Body String jsonObject.toString(), Callback<Response> callback);
}
The only change being JSONObject jsonObject to String jsonObject.toString().
Alternately, you could brute force it by just taking the string that you have have of the JSON and replace '"name_value_pairs": {' with '' and the last '}' in the string with ''. JSON is just a string of text. Other than it being inelegant, there is no reason that you can not manipulate the text. Those two replacements will result in a valid JSON text-object. The whitespace indentation won't look correct to a human, but a machine parsing the JSON string does not care if the whitespace is correct.

Parsing JSON webservice result android

This is part of an AsyncTask that calls a web service that returns a JSON result. As you can see I hard coded the actual JSON return object. This was pulled directly from the error I got that specified it could not create the JSON object from the string object I was passing in, which is the variable result. That error occured when it hit new JSONObject(result) in the ParseResults method. Why would hard coding the exact string work but not the string being passed in?
#Override
protected void onPostExecute(String result) {
try {
result = "{\"Response\":{\"ReturnCode\":200,\"ReturnMessage\":\"Information Successfully Retrieved\",\"ReturnData\":null,\"ReturnClass\":{\"PRO_ID\":\"11111111-1111-1111-1111-111111111111\",\"PRO_FirstName\":\"SILVER\",\"PRO_LastName\":\"HIYO\"},\"FriendlyErrorMessage\":null}}";
JSONObject jsonObject = new ApiMethods().ParseResult(result);
ParseResults method snippet.
public JSONObject ParseResult(String result) throws JSONException
{
JSONObject returnedObject = new JSONObject();
try
{
JSONObject jsonObject = new JSONObject(result);
Also below, as i stated in a comment to another user, is the return statement that is returning the data. This is being returned from a .NET MVC application. I added in the UTF8 when that was mentioned and still get the same error.
return Json(data: new { Response = returnValue }, contentType: "application/json", contentEncoding: System.Text.Encoding.UTF8, behavior: JsonRequestBehavior.AllowGet);
And the entire error message:
org.json.JSONException: Value {"Response":{"ReturnCode":200,"ReturnMessage":"Information Successfully Retrieved","ReturnData":null,"ReturnClass":{"PRO_ID":"11111111-1111-1111-1111-111111111111","PRO_FirstName":"Silver","PRO_LastName":"HIYO"},"FriendlyErrorMessage":null}} of type java.lang.String cannot be converted to JSONObject
Seems like your hardcoded json object is not a valid json object. This may be the reason why it throws exception. Check validitiy of json object here first.
type java.lang.String cannot be converted to JSONObject
This means "Use getString() for String"
getJSONObject() may cause this error.
class Response {
String returnMessage;
...
}
Response response;
response.returnMessage= "msg";
JSONObjct obj;
obj = response.getJSONObject("ReturnMessage"); // cannot be converted
It maybe a encoding problem. Browser (and source editor) may have converted the result string encoding.
Q: ... I am storing items for the JSON data as Strings which is resulting in some odd character appearing
A: new String(jo.getString("name").getBytes("ISO-8859-1"), "UTF-8");
Android JSON CharSet UTF-8 problems
Hard coded JSON string is valid. If you want to try, replace (\") with (") and paste it to the checker.
{
"Response": {
"ReturnCode": 200,
"ReturnMessage": "Information Successfully Retrieved",
"ReturnData": null,
"ReturnClass": {
"PRO_ID": "11111111-1111-1111-1111-111111111111",
"PRO_FirstName": "SILVER",
"PRO_LastName": "HIYO"
},
"FriendlyErrorMessage": null
}
}
JSON object is like a structure (or class)
It looks like this.
class Response {
int ReturnCode = 200;
String ReturnMessage = "Information Successfully Retrieved";
...
}
Sample code.
protected void onPostExecute(String result)
{
JSONObject jsonObject;
JSONObject response;
int returnCode;
String returnMessage;
//JSONObject returnMessage;
result = "{\"Response\":{\"ReturnCode\":200,\"ReturnMessage\":\"Information Successfully Retrieved\",\"ReturnData\":null,\"ReturnClass\":{\"PRO_ID\":\"11111111-1111-1111-1111-111111111111\",\"PRO_FirstName\":\"SILVER\",\"PRO_LastName\":\"HIYO\"},\"FriendlyErrorMessage\":null}}";
try
{
jsonObject = new JSONObject(result);
response = jsonObject.getJSONObject("Response");
returnCode = response.getInt("ReturnCode");
returnMessage = response.getString("ReturnMessage");
//returnMessage = response.getJSONObject("ReturnMessage"); // This may cause same error
}
catch (JSONException e)
{
e.printStackTrace();
}
}
Use this site to validate your json string
http://jsonlint.com/

Categories

Resources