GSON: Expected a string but was BEGIN_OBJECT? - android

I'm trying to use GSON to parse some very simple JSON. Here's my code:
Gson gson = new Gson();
InputStreamReader reader = new InputStreamReader(getJsonData(url));
String key = gson.fromJson(reader, String.class);
Here's the JSON returned from the url:
{
"access_token": "abcdefgh"
}
I'm getting this exception:
E/AndroidRuntime(19447): com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected a string but was BEGIN_OBJECT at line 1 column 2
Any ideas? I'm new to GSON.

The JSON structure is an object with one element named "access_token" -- it's not just a simple string. It could be deserialized to a matching Java data structure, such as a Map, as follows.
import java.util.Map;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
public class GsonFoo
{
public static void main(String[] args)
{
String jsonInput = "{\"access_token\": \"abcdefgh\"}";
Map<String, String> map = new Gson().fromJson(jsonInput, new TypeToken<Map<String, String>>() {}.getType());
String key = map.get("access_token");
System.out.println(key);
}
}
Another common approach is to use a more specific Java data structure that matches the JSON. For example:
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
public class GsonFoo
{
public static void main(String[] args)
{
String jsonInput = "{\"access_token\": \"abcdefgh\"}";
Response response = new Gson().fromJson(jsonInput, Response.class);
System.out.println(response.key);
}
}
class Response
{
#SerializedName("access_token")
String key;
}

Another "low level" possibility using the Gson JsonParser:
package stackoverflow.questions.q11571412;
import com.google.gson.*;
public class GsonFooWithParser
{
public static void main(String[] args)
{
String jsonInput = "{\"access_token\": \"abcdefgh\"}";
JsonElement je = new JsonParser().parse(jsonInput);
String value = je.getAsJsonObject().get("access_token").getAsString();
System.out.println(value);
}
}
If one day you'll write a custom deserializer, JsonElement will be your best friend.

This is normal parsing exception occurred when Pojo key data type is different from json response
This is due to data type mismatch in Pojo class and actually data which comes in the Network api Response
Eg
data class ProcessResponse(
val outputParameters: String,
val pId: Int
)
got the same error due to api gives response as
{
"pId": 1",
"outputParameters": {
"": ""
}
}
Here POJO is outputParameters is String but as per api response its json

Related

Getting JSON Array And JSON object in same key

i am getting response in Json array and json object in same key.Json Array is working fine but while parsing json Object i am getting an error
Caused by: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was
BEGIN_OBJECT at line 1 column 204 path $.RenewalPlans.RenewalPlan
Json Object
{"Code":"000","Message":"Success","UserName":"abc","CustomerName":"abc And
Company","PaymentMessage":"You have 55 days left, you can make ADVANCE
payment","RenewalPlans":{"RenewalPlan":{"PlanId":"11111","PlanName":"plan
name","PlanAmount":"1000"}}}
Json Array
{"Code":"000","CustomerName":"abc","Message":"Success","PaymentMessage":"You have 2 days left, you can make ADVANCE payment","RenewalPlans":{"RenewalPlan":[{"PlanAmount":"100","PlanId":"1","PlanName":"Value Standard 25mbps/12mths 1TV (Renew) "},{"PlanAmount":"200","PlanId":"2","PlanName":"30Mbps/12mths SPECIAL OFFER 2077 (1TV) "},{"PlanAmount":"300","PlanId":"3","PlanName":"40Mbps/12mths SPECIAL OFFER 2077 (2TV) (Rs.19775)"},{"PlanAmount":"400","PlanId":"4","PlanName":"60Mbps/12mths SPECIAL OFFER 2077 (3TV) "}]},"Username":"abcd"}
`
String data;
Object json = null;
CustomerdetailsResponse customerDetailsResponse = new Gson().fromJson(new Gson().toJson(response), CustomerdetailsResponse.class);
data = new Gson().toJson(customerDetailsResponse.getRenewalPlans().getRenewalPlan());
try {
json = new JSONTokener(data).nextValue();
if (json instanceof JSONObject) {
CustomerDetailsResponseRenewalPlansRenewalPlan plans = new Gson().fromJson(new Gson().toJson(data), CustomerDetailsResponseRenewalPlansRenewalPlan.class);
renewalPlans.add(plans);
}
//you have an object
else if (json instanceof JSONArray) {
renewalPlans = new Gson().fromJson(data, new TypeToken<ArrayList<RenewalPlans>>() {
}.getType());
}
} catch (JSONException e) {
e.printStackTrace();
}
factory register with Gson
public Gson gson()
{
return Converters.registerAll(new GsonBuilder())
.registerTypeAdapterFactory(AppTypeAdapterFactory.create())
.setLenient()
.create();
}
GsonType Adapter factory
#GsonTypeAdapterFactory
public abstract class AppTypeAdapterFactory implements TypeAdapterFactory {
public static TypeAdapterFactory create(){
return new AutoValueGson_AppTypeAdapterFactory();
}
}

Custom GSON parsing

I have the following pojo:
public class PageRedirect implements Parcelable {
#SerializedName("method") private String method;
#SerializedName("url") private String url;
#SerializedName("parameters") private Parameters parameters;
//#SerializedName("parameters") private String params;
......}
The parameters field is changing depends on some parameter with the originating API. So sometimes it is {} "json object" and if it is empty, it is array []. I know this is a fault in the Backend. But I would like to find a quick work around... Instead of parsing the parameters, I just would like to get it as a string as the commented line and then I will process it. Any ideas?
When creating your instance of Gson, you can set a custom class deserializer as follows:
final GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Parameter.class, new ParameterTypeAdapter());
final Gson gson = gsonBuilder.create();
PageRedirect pageRedirect = gson.fromJson(yourJsonString, PageRedirect.class);
Then you can create your ParameterTypeAdapter as follows:
public class ParameterTypeAdapter extends TypeAdapter<Parameter> {
#Override
public void write(JsonWriter out, Calendar value) throws IOException {
}
#Override
public Calendar read(JsonReader in) throws IOException {
// do your parsing here
}
You can find more info on it here and here.
EDIT:
If you just want to defer parsing to another moment, you can store your "parameters" field as a JsonElement:
#SerializedName("parameters") private JsonElement parameters;
Afterwards, just convert it to String by using parameters.toString();

GSON JSON parsing returns null

This is the code I have been trying to parse using GSON, from an array of custom type.
class Message{
String username;
String text;
String user_pic;
public Message(String un, String msg){
username=un; text=msg;
}
}
Message[] messages = new Message[2];
messages[0]=new Message("rory","hi");
messages[1]=new Message("van","where's my money!");
String JSON2 = new Gson().toJson(messages, Message[].class);
returns "[null,null]"
ended up using:
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
couldn't get GSON to work.
Try this to convert your custom array to Json string using Gson library.
String jsonString = new Gson().toJsonTree(messages).toString();
Refer Gson API documentation for more details. Hope this will be helpful.

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.

Android: convenient method for parsing this kind of string

I have the following string:
{
"id":398225253590019,
"zip":"11375",
"street":"70-30 Austin St.",
"state":"NY",
"longitude":-73.845858172784,
"latitude":40.720457257566,
"country":"United States",
"city":"Forest Hills"
}
Please can anyone suggest me a convenient method for parsing it so that I can make a single object of the various components.
import org.json.JSONException;
import org.json.JSONObject;
...
...
String jsonstring = "{
"id":398225253590019,
"zip":"11375",
"street":"70-30 Austin St.",
"state":"NY",
"longitude":-73.845858172784,
"latitude":40.720457257566,
"country":"United States",
"city":"Forest Hills"
}";
JSONObject jObject = null;
try{
jObject = new JSONObject(jsonstring);
catch(JSONException e) {
//Json parse error usually
}
It is a JSON.
You can parset the String into JSONObject. Look the example of JSONTokenizer
That format is called json:
1.You can first create an object (Say "Object") with variables id,zip,country etc and getters and setters.
2.Download Link for jackson.
3.Import the library to your project.
Then just two lines of code:
ObjectMapper mapper = new ObjectMapper();
Object object = mapper.readValue(json, Object.class);
This Object class will contain the values...
Jackson Tutorial.

Categories

Resources