How to use gson parse hetorogeneous map - android

I want to parse a sample json by gson like this:
"category": {
"sub_category_1": [...],
"sub_category_2": [...],
"sub_category_3": {...}
}
Because all sub categories are dynamic and I'm only interested in sub categories which are maps. So I'm using Map<String, Map<String, String>> as data type in POJO. However, I got error saying array is expected. My guess is that it's also using that data type to parse when sub category is an array. Any suggestion? I'm new to Retrofit and Gson, so it would be great if you can paste your deserializer code here.

You have to use a custom TypeAdapter for Gson. It's a hard and messy job, but it's the only way I found to make the parsing viable. Take a look at these:
http://www.javacreed.com/gson-typeadapter-example/
http://www.studytrails.com/java/json/java-google-json-type-adapter.jsp
https://google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/com/google/gson/TypeAdapter.html

Related

Parsing API results on Android with Retrofit and Jackson or Gson

I am trying to parse the results of an API call which returns a unique first property.
{
"AlwaysDifferent12345": {
"fixedname1" : "ABC1",
"fixedname2" : "ABC2"
}
}
I am using retrofit2 and jackson/gson and cannot figure out how to cope with dynamic property names within the retrofit2 framework. The following works fine
data class AlwaysDifferentDTO(
#JsonProperty("AlwaysDifferent12345") val alwaysDifferentEntry: AlwaysDifferentEntry
)
I have tried
data class AlwaysDifferentDTO(
#JsonProperty
val response: Map<String, AlwaysDifferentEntry>
)
But this returns errors Can not instantiate value of type... The return value from the API is fixed i.e. map<string, object>.
I have read you can write a deserializer but it looks like I need to deserialize the whole object when all I want to do is just ignore the string associated with the response.
I have read
https://discuss.kotlinlang.org/t/set-dynamic-serializedname-annotation-for-gson-data-class/14758
and several other answers. Given unique properties names are quite common it would be nice to understand how people deal with this when using retrofit2
Thanks
Because the JSON doesn't have a 1-to-1 mapping Jackson can't map it automatically using annotations. You are going to need to make your own Deserializer.
In this tutorial you can learn how to create your own custom Deserializer for Jackson. https://www.baeldung.com/jackson-deserialization
In the tutorial you will see the first line under the deserialize function is
JsonNode node = jp.getCodec().readTree(jp);
using this line you can get the JSON node as a whole and once you have it you can call this function
JsonNode AlwaysDifferent12345Node = node.findParent("fixedname1");
Now that you have that node you can retrieve its value like shown in the rest of the tutorial. Once you have all the values you can return a new instance of the AlwaysDifferentDTO data class.

Android. How to parse JsonArrays inside JsonArray

I use retrofit and json. I need to parse a json like that:
{
"outer_array": [
"one" : [{}, {}],
"two" : [{}],
"three" : [{}],
....
]
}
Here is part of my code:
#SerializedName("outer_array") var data: List<List<Data>>
But how can I parse each element of the "outer_array" array by key. Arrays inside "outer_array" can be from 0 to n. Maybe I should use a TypeAdapter. But I don't know how to apply it for this case, please help me
The JSON you've provided is not valid. You can check it on JSONLint. I guess it should be either an array (without "one" :) or an object ([ in front of outer_array should be {) in the first case your code is fine and in second case you can use a Map (like HashMap) and if you need to convert that map to array you can use something like this
data class MyClass(
#SerializedName("outer_array") var data: HashMap<String, List<Data>>
){
val dataAsArray get() = data.map{ it.value }
}
But if you have to parse this invalid data (e.g you cannot ask the provider/backend to fix this) even a TypeAdapter cannot help, because the JSON is invalid and you'll face an exception, you can use a regex to replace invalid [ ] with { } (but this is so dumb, try to convince the backend dev to fix the json :D)
I suggest you to use Gson, a Google service to parse JSON strings into Objects and viceversa. Simple add "implementation 'com.google.code.gson:gson:2.8.6'" into dependencies in the app's Gradle file in your Android project.
You could use two methods: toJson(Object obj) and fromJson(string json, Class<>)
if you have a class called 'MyObject', you have to put as second parameter of 'fromJson': MyObject.class, or MyObject[].class if an array.
GitHub: https://github.com/google/gson

Parsing json list when there is an exceptional objects as well using Retrofit2

Previously I was receiving the response like this:
I was parsing it like: Call<List<MyObject>> getList();
But now there are some new elements were added and the response changed to:
How to parse this object now? I searched my could not find any solutions.
This is how I am setting up my client.
This is the json object which i recieve as a response:
{"map":{"01":{"F":".","E":".","D":null,"C":null,"B":".","A":"."},"02":{"F":".","E":".","D":null,"C":null,"B":"Z","A":"."},"03":{"F":"A","E":"A","D":null,"C":null,"B":"A","A":"A"},"board":false,"type":{"num":"TT334","board":"WW","date":"31MAR","route":"AWETSW","pcount":""}}}
I dont
There are two potential solutions:
You create a DTO. Gson will ignore fields you don't map in your dto. Your json doesn't use a list it is entirely objects.
You manually parse the json using Gson's JsonReader
You can use a mixture of DTOs and manual parsing. I have done this for large json datasets and inconsistent datasets.

How to parse json page using gson?

I have a large json page which contains url:http://akhilmadanan.tk/Akhil/database.php.
While i am parsing this page using normal json parsing method it shows "OutOfMemoryError". For this i heard about GSON. Please any body help me get how to read the datas from below page using GSON.
any tutorial?
Here'a good tutorial:
http://www.javacodegeeks.com/2011/01/android-json-parsing-gson-tutorial.html
You can also check out their official user guide:
https://sites.google.com/site/gson/gson-user-guide
Hope this helps :-)
Instead of returning all the data, why don't you break it into chunks? That would require less memory at processing time.
Thats assuming you have access to the database level/response.
You can definitely go to links provided by others which are helpful
For brief you can add GSON library in your lib folder.
and use like this.
Gson gson=new Gson();
To get object from json
Model model=gson.fromJson(json,Model.class);
To convert to json
String json=gson.toJson(model);
I run your code and there are 3010 items of object
[
{
"cust_no":"70105615002",
"cust_name":"akhil",
"address":"kajffjkhfhhkjsd",
"area":"58695",
"ranges":"4586",
"plot":"69896",
"multifactor":"85758",
"electricity_meterno":"7895",
"water_meterno":"69358",
"gas_metrno":"78956",
"traffic_code":"4587855",
"last_meter":"58695",
"previous_reading":"25638",
"date":"589687",
"current_usage":"789654",
"current_balance":"45876",
"last_recipt":"236584"
},....
Now make a model equivalent to above name like
#SerializedName("cust_no")
private Long custNo;
#SerializedName("cust_name")
private Long custName;
..........
remember to add one list of same class type like
#SerializedName("custname")
private List<Customer> customerList;
and generate getters and setters of that Customer class;
after this
parse your data like this
CustomerModel customerModel=gson.fromJson(json,Customer.class);
you get all your data in customerModel;
To access data just use list of that class.
List<Customer> customerList=customerModel.getCustomerList();
Log.v("APP_NAME",""+customerList.size());

Parsing an object with variable type in gson

I have something like the following json string:
{"values" : [
{ "group":"A"
"rating":2
},
{
"group":"B"
"language":"english"
}
]
}
As you can see, "values" is an array, with different type of objects. One type can contain a string and an integer, and the other type contains a string and another string.
How do I deal with this?
Sorry, I didn't notice originally you wrote "gson". I'm not sure you can do it, and here's not me saying it.
Do some thing like the following
List myStrings = new ArrayList();
myStrings = gson.fromJson(json,myStrings.getClass());
Iterator myIterator = myStrings.iterator();
boolean b;
while(myIterator.hasNext()){
Object o =myIterator.next();
b=o instanceof String;
System.out.println("...."+b);
}
My approach would probably be to implement a polymorphic deserialization solution.
Gson does not currently have a simple mechanism for polymorphic deserialization, other than implementing custom deserialization processing. The next release looks like it will provide a built-in solution.
Previous StackOverflow.com Questions And Answers (Some With Examples) On This Topic:
Deserialising a generic with unknown compile time type where a field indicates the type
Parse JSON with no specific structure for a field with GSON
json object serialization/deserialization using google gson
Polymorphism with gson
Specific to the original question, it looks like the "group" element would be used to distinguish between different types.
FWIW, Jackson released a built-in solution to this problem many moons ago.

Categories

Resources