How to serialize the response to object by using Gson? - android

I make request directly to VK api with token
Like this: https://api.vk.com/method/groups.get?fields=photo_50&access_token=MY_TOKEN&filter=admin%2C%20editor%2C%20moder&extended=1
Here is spec about api
But I can't serialize the response to object by using Gson, because is response array there is int value:
{
"response": [
2,
{
"gid": 59295,
"name": "Создание",
"screen_name": "book",
"is_closed": 0,
"type": "group",
"photo_50": "https://pp.userapi.com/qwvD6SPkYzo.jpg"
},
{
"gid": 57150,
"name": "Массаж",
"screen_name": "club10450",
"is_closed": 2,
"type": "group",
"photo_50": "https://pp.userapi.com/ZKnmRkS1izs.jpg"
}
]
}
How can I make serialize it to object by using Gson?

Despite you've already resolved the issue by changing the API version via the GET URL parameters, here is a method of dealing with "non-standard" JSONs you might face in the future. I'm assuming you have correct mappings, but the array length (presumably) is put as the very first array element. Gson cannot handle such a special case itself (at least if it expects {...} objects), probably giving you something like this:
Expected BEGIN_OBJECT but was NUMBER at line 3 column 10 path $.response[0]
Assuming you have mappings similar to the next two:
final class ElementsResponse {
#SerializedName("response")
final List<Element> response = null;
}
final class Element {
#SerializedName("gid")
final int gid = Integer.valueOf(0);
#SerializedName("name")
final String name = null;
#SerializedName("screen_name")
final String screenName = null;
#SerializedName("is_closed")
final int isClosed = Integer.valueOf(0);
#SerializedName("type")
final String type = "";
#SerializedName("photo_50")
final URL photo50 = null;
}
You can easily create your type adapter with a special type adapter factory in order to deal with the given JSON:
final class LengthArrayTypeAdapterFactory
implements TypeAdapterFactory {
// The instance holds no state and can be created as a singleton
private static final TypeAdapterFactory lengthArrayTypeAdapterFactory = new LengthArrayTypeAdapterFactory();
private LengthArrayTypeAdapterFactory() {
}
// However, the factory method does not let a caller to create an instance itself, and _may_ create it itself if necessary (encapsulation)
static TypeAdapterFactory getLengthArrayTypeAdapterFactory() {
return lengthArrayTypeAdapterFactory;
}
#Override
public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) {
// Are we dealing with a java.util.List instance?
if ( List.class.isAssignableFrom(typeToken.getRawType()) ) {
// Resolve the list element type if possible
final Type elementType = getElementType(typeToken.getType());
// And request Gson for the element type adapter
final TypeAdapter<?> elementTypeAdapter = gson.getAdapter(TypeToken.get(elementType));
// Some Java boilerplate regarding generics in order not letting the #SuppressWarnings annotation cover too much
#SuppressWarnings("unchecked")
final TypeAdapter<T> castTypeAdapter = (TypeAdapter<T>) new LengthArrayTypeAdapter<>(elementTypeAdapter);
return castTypeAdapter;
}
// Or let Gson pick the next downstream type adapter itself
return null;
}
private static Type getElementType(final Type listType) {
// The given type is not parameterized?
if ( !(listType instanceof ParameterizedType) ) {
// Probably the (de)serialized list is raw being not parameterized
return Object.class;
}
final ParameterizedType parameterizedType = (ParameterizedType) listType;
// Or just take the first type parameter (java.util.List has one type parameter only)
return parameterizedType.getActualTypeArguments()[0];
}
private static final class LengthArrayTypeAdapter<E>
extends TypeAdapter<List<E>> {
// This type adapter is designed to read and write a single element only
// We'll take care of all elements array ourselves
private final TypeAdapter<E> elementTypeAdapter;
private LengthArrayTypeAdapter(final TypeAdapter<E> elementTypeAdapter) {
this.elementTypeAdapter = elementTypeAdapter;
}
#Override
public List<E> read(final JsonReader in)
throws IOException {
// Gson type adapters are supposed to be null-friendly
if ( in.peek() == NULL ) {
return null;
}
// Consume the array begin token `[`
in.beginArray();
// The next value is most likely the array length?
final int arrayLength = in.nextInt();
final List<E> list = new ArrayList<>();
// Read until the array has more elements
while ( in.hasNext() ) {
// And let the element type adapter read the array element so push the value to the list
list.add(elementTypeAdapter.read(in));
}
// Consume the array end token `]`
in.endArray();
assert arrayLength == list.size();
return list;
}
#Override
#SuppressWarnings("resource")
public void write(final JsonWriter out, final List<E> list)
throws IOException {
if ( list == null ) {
// Must be null-friendly always
out.nullValue();
} else {
// Writing the `[` token
out.beginArray();
// Writing the list size/length
out.value(list.size());
for ( final E element : list ) {
// And just write each array element
elementTypeAdapter.write(out, element);
}
// Finalizing the writing with `]`
out.endArray();
}
}
}
}
So all you had to do could be just adding the type adapter factory to the Gson configuration creating your special arrays-aware Gson:
final Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(getLengthArrayTypeAdapterFactory())
.create();
final ElementsResponse elementsResponse = gson.fromJson(JSON, ElementsResponse.class);
elementsResponse.response.forEach(e -> System.out.println(e.name));
System.out.println(gson.toJson(elementsResponse));
Output:
Создание
Массаж
{"response":[2,{"gid":59295,"name":"Создание","screen_name":"book","is_closed":0,"type":"group","photo_50":"https://pp.userapi.com/qwvD6SPkYzo.jpg"},{"gid":57150,"name":"Массаж","screen_name":"club10450","is_closed":2,"type":"group","photo_50":"https://pp.userapi.com/ZKnmRkS1izs.jpg"}]}
Note that this type adapter factory always assumes that the first array element is a number, and you might need to analyze the elementType if necessary (for example, if it's a java.lang.Number or its subclass).

Resolved, Added param to url v=5.61 version number
{
"response": {
"count": 190,
"items": [{
"id": 28261334,
"name": "TJ",
"screen_name": "tj",
"is_closed": 0,
"type": "page",
"is_admin": 0,
"is_member": 1,
"photo_50": "https://pp.vk.me/...f2c/06crfCSL1KY.jpg"
}]
}
}

Related

Android kotlin object to json values order [duplicate]

Seems like Gson.toJson(Object object) generates JSON code with randomly spread fields of the object. Is there way to fix fields order somehow?
public class Foo {
public String bar;
public String baz;
public Foo( String bar, String baz ) {
this.bar = bar;
this.baz = baz;
}
}
Gson gson = new Gson();
String jsonRequest = gson.toJson(new Foo("bar","baz"));
The string jsonRequest can be:
{ "bar":"bar", "baz":"baz" } (correct)
{ "baz":"baz", "bar":"bar" } (wrong sequence)
You'd need to create a custom JSON serializer.
E.g.
public class FooJsonSerializer implements JsonSerializer<Foo> {
#Override
public JsonElement serialize(Foo foo, Type type, JsonSerializationContext context) {
JsonObject object = new JsonObject();
object.add("bar", context.serialize(foo.getBar());
object.add("baz", context.serialize(foo.getBaz());
// ...
return object;
}
}
and use it as follows:
Gson gson = new GsonBuilder().registerTypeAdapter(Foo.class, new FooJsonSerializer()).create();
String json = gson.toJson(foo);
// ...
This maintains the order as you've specified in the serializer.
See also:
Gson User Guide - Custom serializers and deserializers
If GSON doesn't support definition of field order, there are other libraries that do. Jackson allows definining this with #JsonPropertyOrder, for example. Having to specify one's own custom serializer seems like awful lot of work to me.
And yes, I agree in that as per JSON specification, application should not expect specific ordering of fields.
Actually Gson.toJson(Object object) doesn't generate fields in random order. The order of resulted json depends on literal sequence of the fields' names.
I had the same problem and it was solved by literal order of properties' names in the class.
The example in the question will always return the following jsonRequest:
{ "bar":"bar", "baz":"baz" }
In order to have a specific order you should modify fields' names, ex: if you want baz to be first in order then comes bar:
public class Foo {
public String f1_baz;
public String f2_bar;
public Foo ( String f1_baz, String f2_bar ) {
this.f1_baz = f1_baz;
this.f2_bar = f2_bar;
}
}
jsonRequest will be { "f1_baz ":"baz", "f2_bar":"bar" }
Here's my solution for looping over json text files in a given directory and writing over the top of them with sorted versions:
private void standardizeFormat(File dir) throws IOException {
File[] directoryListing = dir.listFiles();
if (directoryListing != null) {
for (File child : directoryListing) {
String path = child.getPath();
JsonReader jsonReader = new JsonReader(new FileReader(path));
Gson gson = new GsonBuilder().setPrettyPrinting().registerTypeAdapter(LinkedTreeMap.class, new SortedJsonSerializer()).create();
Object data = gson.fromJson(jsonReader, Object.class);
JsonWriter jsonWriter = new JsonWriter(new FileWriter(path));
jsonWriter.setIndent(" ");
gson.toJson(data, Object.class, jsonWriter);
jsonWriter.close();
}
}
}
private class SortedJsonSerializer implements JsonSerializer<LinkedTreeMap> {
#Override
public JsonElement serialize(LinkedTreeMap foo, Type type, JsonSerializationContext context) {
JsonObject object = new JsonObject();
TreeSet sorted = Sets.newTreeSet(foo.keySet());
for (Object key : sorted) {
object.add((String) key, context.serialize(foo.get(key)));
}
return object;
}
}
It's pretty hacky because it depends on the fact that Gson uses LinkedTreeMap when the Type is simply Object. This is an implementation details that is probably not guaranteed. Anyway, it's good enough for my short-lived purposes...

GSON sorting keys automatically in toJson() [duplicate]

Seems like Gson.toJson(Object object) generates JSON code with randomly spread fields of the object. Is there way to fix fields order somehow?
public class Foo {
public String bar;
public String baz;
public Foo( String bar, String baz ) {
this.bar = bar;
this.baz = baz;
}
}
Gson gson = new Gson();
String jsonRequest = gson.toJson(new Foo("bar","baz"));
The string jsonRequest can be:
{ "bar":"bar", "baz":"baz" } (correct)
{ "baz":"baz", "bar":"bar" } (wrong sequence)
You'd need to create a custom JSON serializer.
E.g.
public class FooJsonSerializer implements JsonSerializer<Foo> {
#Override
public JsonElement serialize(Foo foo, Type type, JsonSerializationContext context) {
JsonObject object = new JsonObject();
object.add("bar", context.serialize(foo.getBar());
object.add("baz", context.serialize(foo.getBaz());
// ...
return object;
}
}
and use it as follows:
Gson gson = new GsonBuilder().registerTypeAdapter(Foo.class, new FooJsonSerializer()).create();
String json = gson.toJson(foo);
// ...
This maintains the order as you've specified in the serializer.
See also:
Gson User Guide - Custom serializers and deserializers
If GSON doesn't support definition of field order, there are other libraries that do. Jackson allows definining this with #JsonPropertyOrder, for example. Having to specify one's own custom serializer seems like awful lot of work to me.
And yes, I agree in that as per JSON specification, application should not expect specific ordering of fields.
Actually Gson.toJson(Object object) doesn't generate fields in random order. The order of resulted json depends on literal sequence of the fields' names.
I had the same problem and it was solved by literal order of properties' names in the class.
The example in the question will always return the following jsonRequest:
{ "bar":"bar", "baz":"baz" }
In order to have a specific order you should modify fields' names, ex: if you want baz to be first in order then comes bar:
public class Foo {
public String f1_baz;
public String f2_bar;
public Foo ( String f1_baz, String f2_bar ) {
this.f1_baz = f1_baz;
this.f2_bar = f2_bar;
}
}
jsonRequest will be { "f1_baz ":"baz", "f2_bar":"bar" }
Here's my solution for looping over json text files in a given directory and writing over the top of them with sorted versions:
private void standardizeFormat(File dir) throws IOException {
File[] directoryListing = dir.listFiles();
if (directoryListing != null) {
for (File child : directoryListing) {
String path = child.getPath();
JsonReader jsonReader = new JsonReader(new FileReader(path));
Gson gson = new GsonBuilder().setPrettyPrinting().registerTypeAdapter(LinkedTreeMap.class, new SortedJsonSerializer()).create();
Object data = gson.fromJson(jsonReader, Object.class);
JsonWriter jsonWriter = new JsonWriter(new FileWriter(path));
jsonWriter.setIndent(" ");
gson.toJson(data, Object.class, jsonWriter);
jsonWriter.close();
}
}
}
private class SortedJsonSerializer implements JsonSerializer<LinkedTreeMap> {
#Override
public JsonElement serialize(LinkedTreeMap foo, Type type, JsonSerializationContext context) {
JsonObject object = new JsonObject();
TreeSet sorted = Sets.newTreeSet(foo.keySet());
for (Object key : sorted) {
object.add((String) key, context.serialize(foo.get(key)));
}
return object;
}
}
It's pretty hacky because it depends on the fact that Gson uses LinkedTreeMap when the Type is simply Object. This is an implementation details that is probably not guaranteed. Anyway, it's good enough for my short-lived purposes...

Deserialize json with same key but different type in android using Jackson

I am calling web-services which can have 2 types of json object in response. Now sometimes i get key profile with type String and sometimes it may have same key with type 'ProfileSubObject'. So how to manage this case? Below are my two types of object. I am using Jackson library to parse json.
1.)
{
"data": [
{
"profession": "iOS Developer",
"thanks": {
"count": 5
},
"profile": "test"
}
]
}
2.)
{
"data": [
{
"profession": "iOS Developer",
"thanks": {
"count": 5
},
"profile": {
"val1":"test1",
"val2":"test2"
}
}
]
}
Key profile have 2 different type of object based on web-service call.
Following is my data class structure.
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonIgnoreProperties(ignoreUnknown = true)
public class DataObject {
#JsonProperty("profession")
private String profession;
#JsonProperty("profile")
private ProfileObject profile;
#JsonProperty("thanks")
private ThanksObject thanks;
public String getProfession() {
return profession;
}
public ThanksObject getThanks() {
return thanks;
}
public ProfileObject getProfile() {
return profile;
}
}
And Profile class is as per below.
public class ProfileObject {
ProfileObject(){
}
ProfileObject(ProfileSubObject profileSubObject){
this.profileSubObject= profileSubObject;
}
ProfileObject(String profile){
this.profile= profile;
}
private ProfileSubObject profileSubObject;
private String profile;
public ProfileSubObject getProfileSubObject() {
return profileSubObject;
}
}
Now when i parse my object, ProfileObject is always null. I want it to get parsed based on proifle key data type.
Anyone could help me with parsing?
In constructing the solution, I faced two problems:
the Json structure does not match a single DataObject
the original problem of deserializing same property into differnt types of Java objects.
The first problem I solved by constructing JavaType objects which tell Jackson the generic type of the collections involved. There are two such collections: a Map, consisting of a single entry with key "data" and value of List of DataObjects
The second problem, I solved with the Jackson feature of #JsonAnySetter which directs Jackson to call a single method for all properties it doesn't recognize. For this purpose, I added #JsonIgnore to the profile variable to make sure that Jackson indeed doesn't recognize it. Now Jackson calls the same method for the two input jsons
This is the new DataObject class:
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonIgnoreProperties(ignoreUnknown = true)
public class DataObject
{
#JsonProperty("profession")
public String profession;
#JsonIgnore // forcing jackson to not recognize this property
public ProfileObject profile;
#JsonProperty("thanks")
public ThanksObject thanks;
public String getProfession() { return profession; }
public void setProfession(String p) { profession = p; }
public ThanksObject getThanks() { return thanks; }
public void setThanks(ThanksObject t) { thanks = t; }
public ProfileObject getProfile() { return profile; }
public void setProfile(ProfileObject p) { profile = p; }
#JsonAnySetter
public void setProfileFromJson(String name, Object value)
{
// if value is single String, call appropriate ctor
if (value instanceof String) {
profile = new ProfileObject((String)value);
}
// if value is map, it must contain 'val1', 'val2' entries
if (value instanceof Map) {
ProfileSubObject profileSubObject =
new ProfileSubObject(((Map<String, String>)value).get("val1"), ((Map<String, String>)value).get("val2"));
profile = new ProfileObject(profileSubObject);
}
// error?
}
}
Here is my test method, which includes the java type construction I mentioned:
public static void main(String[] args)
{
try (Reader reader = new FileReader("C://Temp/xx2.json")) {
ObjectMapper mapper = new ObjectMapper();
// type of key of map is String
JavaType stringType = TypeFactory.defaultInstance().constructType(String.class);
// type of value of map is list of DataObjects
JavaType listOfDataObject = TypeFactory.defaultInstance().constructCollectionType(List.class, DataObject.class);
// finally, construct map type with key and value types
JavaType rootMap = TypeFactory.defaultInstance().constructMapType(HashMap.class, stringType, listOfDataObject);
Map<String ,List<DataObject>> m = mapper.readValue(reader, rootMap);
DataObject do1 = m.values()
// get first (only?) value in map (it is list)
.stream().findFirst().orElse(Collections.emptyList())
// get first (only?) item in list - it is the DataObject
.stream().findFirst().orElse(null);
System.out.println(do1.profile);
System.out.println(do1.profile.profile);
System.out.println(do1.profile.profileSubObject.val1 + " " + do1.profile.profileSubObject.val2);
} catch (Exception e) {
e.printStackTrace();
}
}
This may be of help in regards to parsing JSON, use a JsonReader. It does assume you are using RESTful webservice and have already gotten a HttpURLConnection and an InputStream from the connection.
https://developer.android.com/reference/android/util/JsonReader.html

Use GSON to map changing field name to POJO

I am writing an Android app, and using RetroFit to communicate with the REST API. I have all the classes/POJO's written, except one.
Here is the Java for the specific class.
This is the parent class, which is the root of the problem. I need to be able to map the userNameResponse variable to the users name in the JSON below
public class DiTopicStats {
private UserNameResponse userNameResponse;
public UserNameResponse getUserNameResponse() {
return userNameResponse;
}
public void setUserNameResponse(UserNameResponse userNameResponse) {
this.userNameResponse = userNameResponse;
}
}
and the child class, which should be fine as long as I can map to it from the above parent class:
public class UserNameResponse {
//Fields
//Getters and Setters
}
The JSON that is returned contains a field which changes per response. The field is the users name. For example:
{
"sMessage": "",
"diStatus": {
"diTopicWrongAns": {
//Some fields
},
"diOverallStats": {
//Some more fields
},
"diUserStats": {
"John Smith": { //PROBLEM: This name changes
//some other fields
}
}
}
}
So in this case, the name "John Smith" has a dynamic field name. Realistically, it could be any string with letters, numbers, a - or a . in it.
My question is, using RetroFit, how can I create a Java class that lets RetroFit map a field to a variable?
I'm aware you can specify a SerialisedName but can this be done programatically at runtime, because I will have the name or the user at this stage.
Thanks.
Create a pojo called DiUserStats and then define a custom GsonTypeAdapter e.g.
public class DiUserStatsTypeAdapter implements JsonDeserializer<DiUserStats>, JsonSerializer<DiUserStats> {
#Override
public DiUserStats deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
DiUserStats target = new DiUserStats();
JsonObject jsonObject = json.getAsJsonObject();
Map.Entry<String,JsonElement> object =(Map.Entry<String,JsonElement>)jsonObject.entrySet().toArray()[0];
target.setName(object.getKey());
JsonObject targetValues = object.getValue().getAsJsonObject();
/*parse values to your DiUserStats as documented using targetValues.get("fooProperty").getAsString(), etc */
return target;
}
#Override
public JsonElement serialize(DiUserStats src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject obj = new JsonObject();
JsonObject values = new JsonObject();
values.addProperty("foo", src.getFoo);
obj.addProperty(target.getName(), values);
return obj;
}
}
Then when you setup Gson use a builder and add your custom type adapter e.g.
Gson gson = new GsonBuilder().registerTypeAdapter(DiUserStats.class, new DiUserStatsTypeAdapter()).create();

Gson Parse Json with array with different object types

How can I parse this JSON using Gson?
I have an array with multiple object types and I don't know what kind of object I need to create to save this structure. I cannot change the json message (I don't control the server).
The only class that function (sort of) was this
public class Response {
private List<Object> tr;
private int results;
(...)
}
JSON Message (Note the array with multiple object types.)
{
"tr":
[
{
"a":
{
"userId": "112"
}
},
{
"b":
{
"userId": "123",
"address":"street dummy"
}
},
{
"a":
{
"userId": "154"
}
}
],
"results":3
}
The Gson User's Guide explicitly covers this:
https://sites.google.com/site/gson/gson-user-guide#TOC-Serializing-and-Deserializing-Collection-with-Objects-of-Arbitrary-Types
You have an object with a field tr that is an array containing arbitrary types.
The users guide explains that you can't directly deserialize such a structure, and recomends:
Use Gson's parser API (low-level streaming parser or the DOM parser
JsonParser) to parse the array elements and then use Gson.fromJson()
on each of the array elements. This is the preferred approach.
In your case ... it would really depend on what objects were possible in that array. If they are all going to have that same inner object you'd want to do something like...
List<MyUserPojo> list = new ArrayList<MyUserPojo>();
JsonArray array = parser.parse(json).getAsJsonObject().getAsJsonArray("tr");
for (JsonElement je : array)
{
Set<Map.Entry<String,JsonElement>> set = je.getAsObject().entrySet();
JsonElement je2 = set.iterator().next().getValue();
MyUserPojo mup = new Gson().fromJson(je2, MyUserPojo.class);
list.add(mup);
}
And of course, this would need to be inside a custom deserializer for your actual object that would have the tr and results fields.
class MyPojo
{
List<MyUserPojo> userList;
int results;
}
class MyUserPojo
{
String userId;
String address;
}
class MyDeserializer implements JsonDeserializer<MyPojo>
{
#Override
public MyPojo deserialize(JsonElement je, Type type, JsonDeserializationContext jdc)
throws JsonParseException
{
List<MyUserPojo> list = new ArrayList<MyUserPojo>();
JsonArray array = je.getAsJsonObject().getAsJsonArray("tr");
for (JsonElement je2 : array)
{
Set<Map.Entry<String,JsonElement>> set = je2.getAsObject().entrySet();
JsonElement je3 = set.iterator().next().getValue();
MyUserPojo mup = new Gson().fromJson(je3, MyUserPojo.class);
list.add(mup);
}
MyPojo mp = new MyPojo();
mp.tr = list;
mp.results = je.getAsObject().getAsJsonPrimitive("results").getAsInt();
return mp;
}
}
Now you're all set - you can use that deserializer and create your object:
Gson gson = new GsonBuilder()
.registerTypeAdapter(MyPojo.class, new MyDeserializer())
.build();
MyPojo mp = gson.fromJson(json, MyPojo.class);
If the a, b etc are important ... well, you'll have to figure that out. But the above should get you well on your way to understanding what's going to be needed to deal with your JSON structure.
For completeness sake, the only "hacky" way around this is if there is a fairly limited number of those types and the inner object also is fairly limited in terms of its fields. You could create a POJO that encompasses all the possibilities:
class MyPojo
{
MySecondPojo a;
MySecondPojo b;
...
MySecondPojo f;
}
class MySecondPojo
{
String userId;
String address;
...
String someOtherField;
}
When Gson deserializes JSON it will set any missing fields in your POJO(s) to null. You could now have tr be a List or array of these in your POJO. Again and to emphasize, this is really quite hacky and the wrong way to do it, but I thought I'd explain what would be required to directly parse that array.
I pick something from each answer and did it this way:
Response Object
public class Response {
private List<Users> tr;
private int results;
(...)
}
Generic User
public class User {
public static final int TYPE_USER_A =0;
public static final int TYPE_USER_B =1;
private String userId;
private int type;
(...)
}
A
public class a extends User {
private String location;
(...)
}
B
public class b extends User {
private String adress;
(...)
}
Parsing Method
private Response buildResponseObject(String response) {
Response tls = new Response();
List<Users> users = new ArrayList<users>();
User u;
try {
JSONObject object = new JSONObject(response);
tls.setResults(object.getInt("results"));
JSONArray array = object.getJSONArray("tr");
for (int i = 0; i < array.length(); i++) {
JSONObject trs = array.getJSONObject(i);
if (trs.has("a")) {
String json = trns.getString("a");
A a = new Gson().fromJson(json,A.class);
a.setType(User.TYPE_USER_A);
users.add(a);
} else if (trs.has("b")) {
String json = trs.getString("b");
B b= new Gson().fromJson(json,B.class);
B.setType(User.TYPE_USER_B);
users.add(b);
}
}
tls.setUsers(users);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return tls;
}
This is not as elegant as I wanted and mix native JsonObjects with Gson methods but works for me.
Try this code here:
public class Address {
public String userId;
public String address;
// ...
}
public class Response {
private HashMap<String, Address> tr;
private int results;
// ...
}
Usage:
String json = "{\n \"tr\":\n {\n \"a\": {\n \"userId\": \"112\"\n },\n \"b\": {\n \"userId\": \"123\",\n \"address\":\"street dummy\"\n },\n \"c\": {\n \"userId\": \"154\"\n }\n },\n \"results\":3\n}";
Response users = new Gson().fromJson(json, Response.class);
As you may see I needed to modify the structure:
{
"tr":
{
"a": {
"userId": "112"
},
"b": {
"userId": "123",
"address":"street dummy"
},
"c": {
"userId": "154"
}
},
"results":3
}
But unfortunately I don't get it managed to allow multiple keys. Right now I have no idea how to fix this.
I think this link might help you:
https://sites.google.com/site/gson/gson-user-guide#TOC-Collections-Examples
Basically, create a class for your "object" (kind of user I guess), and then use the deserialization code of Gson, like this:
Type collectionType = new TypeToken<Collection<User>>(){}.getType();
Collection<User> users= gson.fromJson(json, collectionType);
You can create corresponding java classes for the json objects. The integer, string values can be mapped as is. Json can be parsed like this-
Gson gson = new GsonBuilder().create();
Response r = gson.fromJson(jsonString, Response.class);
Here is an example- http://rowsandcolumns.blogspot.com/2013/02/url-encode-http-get-solr-request-and.html

Categories

Resources