I have three nested classes as the following:
public class A {
String s1;
String s2;
String s3;
String s4;
String s5;
String s6;
String s7;
String s8;
B b;
}
public class B{
private Map<String, C> ag = new HashMap<>();
}
public class C{
private Map<String, Boolean> ar = new HashMap<>();
}
Class A is sent as a GET method reply of type JSON to an Android app which consumes the service as shown bellow:
Gson gson = new GsonBuilder()
.enableComplexMapKeySerialization()
.setLenient()
.create();
Retrofit r = new Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
...
However, when running the Android app, I get the following error:
E/Rest GET Error: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line ? column ? B.ag.
Having in mind that If I remove class b field from class A, everything goes smoothly. It seems that gson is unable to deserialize a composed JSON file. So what to do?
Note: The JSON file is retrieved successfully from a Restful webservice using MOXy not Jackson. So there is no option to use #JsonDeserialize.
Below is the returned JSON file:
{"b":{"ag":{"entry":[{"key":"AS2","value":{"ar":{"entry":[{"key":"s1","value":false},{"key":"s2","value":false},{"key":"s3","value":false},{"key":"s4","value":false},{"key":"s5","value":false},{"key":"s6","value":true},{"key":"s7","value":false},{"key":"s8","value":false}]}}},{"key":"AS3","value":{"ar":{"entry":[{"key":"s1","value":false},{"key":"s2","value":true},{"key":"s3","value":true},{"key":"s4","value":false},{"key":"s5","value":false},{"key":"s6","value":false},{"key":"s7","value":false},{"key":"s8","value":true}]}}},{"key":"AS1","value":{"ar":{"entry":[{"key":"s1","value":false},{"key":"s2","value":true},{"key":"s3","value":true},{"key":"s4","value":false},{"key":"s5","value":false},{"key":"s6","value":false},{"key":"s7","value":false},{"key":"s8","value":false}]}}}]}},"s1":"string1","s2":"string2","s3":"string3","s4":"string4","s5":"string5","s6":"string6","s7":"string7","s8":"string8"}
From your class and error provided it seem that you are getting Array at B b; in Class A. We can say exact problem if you share jsonResponse.
----Updated---
Change your Class B
Class B{
private Ag ag;
}
class Ag {
List<Entry> entry;
}
class Entry{
String key;
Value value;
}
class Value{
Ar ar;
}
class Ar{
List<ArEntry> entry;
}
class ArEntry{
String key;
Boolean value;
}
This is how your classes for the jsonResponse you provided.
You can convert any json response to pojo here or you can add Android Studio plugin here.
Related
I'm using retrofit 2 and i defined some POJO to be able to parse my response from ws
public class mPojo
{
public List<mPojo2> field;
}
How can i get the field as a string ?
The answer that fits my needs:
Gson gson = new GsonBuilder().create();
String json = gson.toJson(mPojo.field.get(i));
I am making an API call to Facebook and receiving the following Json object:
{"first_name":"FirstName",
"last_name":"LastName",
"email":"email#email.com",
"picture":{"data":{"is_silhouette":true,"url":"pictureUrl"}},"id":"12345"}
Instead of deserializing the object manually, I am currently using Gson for it, like this:
FacebookProfileModel facebookProfileModel = new Gson().fromJson(object.toString(), FacebookProfileModel.class);
Here's how my POJO looks like:
#SerializedName("first_name")
String mFirstName;
#SerializedName("last_name")
String mLastName;
#SerializedName("email")
String mEmail;
#SerializedName("url")
String mUrl;
Obviously, I am receiving all the values except for the url, since the value is in 2 Json objects: picture and data. I guess one possible solution but not the best would be to create the Picture object within the Facebook Model and then the Data object within the Picture object but feels bad creating 2 more pojos for a String. Any other solutions?
There is no annotation based solution for this. However, the custom de-serializer would resolve this problem.
Custom Deserializer:-
public class FacebookProfileModelDeserializer implements JsonDeserializer<FacebookProfileModel> {
#Override
public FacebookProfileModel deserialize(JsonElement paramJsonElement, Type paramType,
JsonDeserializationContext paramJsonDeserializationContext) throws JsonParseException {
String url = paramJsonElement.getAsJsonObject().get("picture").getAsJsonObject().get("data").getAsJsonObject()
.get("url").getAsString();
FacebookProfileModel facebookProfileModel = new Gson().fromJson(paramJsonElement.getAsJsonObject(),
FacebookProfileModel.class);
facebookProfileModel.setmUrl(url);
return facebookProfileModel;
}
}
Main method:-
public static void main(String[] args) {
String jsonString = "{\"first_name\":\"FirstName\",\"last_name\":\"LastName\",\"email\":\"email#email.com\",\"picture\":{\"data\":{\"is_silhouette\":true,\"url\":\"pictureUrl\"}},\"id\":\"12345\"}";
Gson gson = new GsonBuilder()
.registerTypeAdapter(FacebookProfileModel.class, new FacebookProfileModelDeserializer())
.create();
FacebookProfileModel faceBookProfileModel = gson.fromJson(jsonString, FacebookProfileModel.class);
System.out.println(faceBookProfileModel.toString());
}
I am trying to deserialize my own class with a null value. But my code doesn't work.
My json:
{"Text":null,"Code":0,"Title":"This is Sparta!"}
In my method I do the following:
this.setText(gson.fromJson(jsonObject.getString("Text"), String.class));
this.setTitle(gson.fromJson(jsonObject.getString("Title"), String.class));
this.setCode(gson.fromJson(jsonObject.getString("Faccode"), Integer.class))
I am not deserialize the whole object, because there can be a List<T>, too.
The error:
myapp W/System.err? com.google.gson.JsonSyntaxException: com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 6 path $
myapp W/System.err? at com.google.gson.Gson.assertFullConsumption(Gson.java:786)
myapp W/System.err? at com.google.gson.Gson.fromJson(Gson.java:776)
myapp W/System.err? at com.google.gson.Gson.fromJson(Gson.java:724)
myapp W/System.err? at com.google.gson.Gson.fromJson(Gson.java:696)
First, you must read about how to parse using gson. You can find some example here.
Now you know how to parse, you can still have problem with null values. To solve it you must tell gson to (de)serialize null using
Gson gson = new GsonBuilder().serializeNulls().create();
From the serializeNulls() doc
Configure Gson to serialize null fields. By default, Gson omits all fields that are null during serialization.
EDIT (Not tested, based on doc)
In order to get some distinct value you can do
String json = ""; //Your json has a String
JsonObject jsonObject = new JsonParser().parse(json).getAsJsonObject();
//If null, use a default value
JsonElement nullableText = jsonObject.get("Text");
String text = (nullableText instanceof JsonNull) ? "" : nullableText.getAsString();
String title = jsonObject.get("Title").toString();
int code = jsonObject.get("Code").getAsInt();
Otherwise if you have this pojo
public class MyElement {
#SerializedName("Text")
private String text;
#SerializedName("Title")
private String title;
#SerializedName("Code")
private int code;
}
you can parse using
String json = ""; //Your json has a String
Gson gson = new GsonBuilder().serializeNulls().create();
MyElement myElement = gson.fromJson(json, MyElement.class);
I had a similar problem (an exception thrown on null value) with the following POJO:
public class MyElement {
private String something;
private String somethingElse;
private JsonObject subEntry; // this doesn't allow deserialization of `null`!
}
and this code:
parsedJson = gson.fromJson(json, MyElement.class)
when subEntry returned by the backend was null.
I fixed it by changing the type of subEntry from JsonObject to JsonElement which is a parent class of both JsonObject and JsonNull, to allow deserialization of null values.
public class MyElement {
private String something;
private String somethingElse;
private JsonElement subEntry; // this allows deserialization of `null`
}
To later check for null at runtime, you'd do as follows:
if (parsedJson.subEntry instanceof JsonNull) {
...
} else {
...
}
I have a large group of json objects received from web server. I want to get all the data from all the json objects. For that How do I iterate through the json object so, that all the values can be stored on arraylist..
This is a sample model of my json object received from server. I need all the data (name and city) in two arraylists. For that how do I loop through the json objects. There is no way of getting the data as json array from the server. That's why I asked here. If it was json array, It would have been easier for me. So please help me..
[{"Name":"abin","City":"aa"},{"Name":"alex","City":"bb"},....... a large collection of json objects...]
You could use Gson and parse the string to a java object.
For example you have a class.
public class Location{
private String name;
private String city;
//getters and setters
}
and in your class you could just parse it to Location class
Gson gson=new Gson();
Location[] locations=gson.fromJson(jsonString,Location[].class);
after that you could loop through the locations
for(int i=0;i<locations.length;i++){
System.out.println(locations[i].getName());
}
if you need to separate the city from the name
ArrayList name=new ArrayList();
ArrayList city=new ArrayList();
for(int i=0;i<locations.length;i++){
name.add(locations[i].getName());
city.add(locations[i].getCity());
}
If you know the structure of your JSON String, then use google's Gson() (add the JAR to your project) to deserialize, in 3 easy steps:
Create the Entity class (whatever your object is, I'm giving "Person" as example).
public class Person {
#Expose //this is a Gson annotation, tells Gson to serialize/deserialize the element
#SerializedName("name") //this tells Gson the name of the element as it appears in the JSON string, so it can be properly mapped in Java class
private String name;
#Expose
#SerializedName("lastName")
private String lastName;
#Expose
#SerializedName("streetName")
private String streetName;
//getters and setters follow
}
Create the class into which you deserialize the JSON string. In my example, the JSON string is actually an array of Persons.
public class PersonsList extends ArrayList<Person> implements Serializable{
//nothing else here
}
If the JSON string has a named key, then you don't have to extend ArrayList:
public class PersonsList implements Serializable{
#Expose
#SerializedName("persons")
private ArrayList<Person> persons;
//getters / setters
}
Do the actual deserialization:
String json = "[{person1},{person2},{person3}]";//your json here
Gson gson = new Gson();
PersonsList personsList = gson.fromJson(json, PersonsList.class);
//then, depending on how you build PersonsList class, you iterate:
for(Person p : personsList)//if you extended ArrayList
//or
for(Person p : personsList.getPersons())//if it's the second option
[{"a":
{"b":"c",
"d":"e",
"f":"g"}
{"a2":
{"b":"c2",
"d":"e2",
"f":"g2"}]
This is the JSON data I 'have to' use. Is there any easy way for me to reach, let's say the b values without having to go through a and a2?
Use GSON
You should create a class for that:
public class MyObject {
private A a;
private A a2;
// a and a2 getters here to check if it parses successfully
}
Class A
public class A {
private String b;
private String d;
private String f;
// getters
}
And somewhere where you want to parse:
Type listType = new TypeToken<ArrayList<MyObject >>() {}.getType();
Gson gson = new Gson();
List<MyObject> list = gson.fromJson(yourJsonStringHere, listType);