How to read the object inside a JSON array - android

I have JSON in this format.
I m trying to create serialization class to store the value.
How to read the "personaldata" field?
I am making a separate class PersonalData to read it.
And in my main serialization class I am reading it as
List<PersonalData>personalData
Is it the right way to do it?
If so, how will I fetch the personal data values?
{
"result": [
{
"name": 0,
"age": 1,
"class": 0,
// More data here
"personalData": {
"isMarried": true,
"isEligible": false,
"Indian": true
}
}
]
}

If you are using some parser like GSON or LoganSquare you can use their annotations and it will be really easy to parse JSON directly to your model. Otherwise if you are using native JSON API
You can use something like this
JSONArray arr=new JSONArray(response);
JSONObject personalData=arr.getJSONObject("personalData");

I am making a separate class PersonalData to read it..
Okay, then that is how you access it. By getting that object from some parent Results object.
For example, given some implementation of the below classes, once you deserialize the JSON, you use Results.getResults().get(0).getPersonalData();
public class Results {
ArrayList<ResultData> result;
// TODO: write getResults()
}
public class ResultData {
int name, age, class;
// Some more data
PersonalData personalData;
// TODO: write getPersonalData()
}
public class PersonalData {
boolean isMarried, isEligible, Indian;
}

Related

Best Way to Create Room Database Object

I am New to Room Persistence Library in Android. I have looked into a lot of tutorials related to Room. But something is unclear about it.
I can relate my questions to the below response. If we use #Embedded in "Info", Is it possible to declare info POJO class as separate entity? because inside info I have another object called "preferences". How can I embed that to my Room Database ?
Next is How can I use Awb ArrayList in below sample for Type converters? Note that inside Awb ArrayList has one more "terms" array inside.
I would appreciate if some can show and explain to me the best way to Create Room from the below sample data. I know so many tutorials are there for simple JSON structure, but I didn't find any examples with nested JsonObjects.
{
"hashCode": 10461,
"jobs": [
{
"info": {
"jobDesc": "aaaaa",
"signatureRequired": "true”
"preferences": {
"podRequired": 0,
"eligableForCcod": false,
"signatureRequired": 1
}
},
"awb": [
{
"terms": [
{
"termValue": "INR1500.000",
"termType": "CASH_AMOUNT"
},
{
"termValue": "CTLDk",
"termType": "CX_EN"
}
],
"packagesCount": 1,
"accountId": "AE _MP",
"awb": "1234567878440"
}
]
}
]
}
I don't know if this is the best possible approach, but normally when I have complex objects in Room I define a converter class containing two TypeConverters. The first one converts from the structured object (your POJO class) to a String with GSON library, something like:
#TypeConverter
public String fromPojoToString(MyPojoClass info) {
if (info == null) {
return (null);
}
Gson gson = new Gson();
Type type = new TypeToken<MyPojoClass>() {
}.getType();
return gson.toJson(info, type);
}
The second converter converts from the string (stored inside Room) to the structured object (the POJO class). Something like:
#TypeConverter
public MyPojoClass fromStringtoPojo(String object) {
if (object == null) {
return (null);
}
Gson gson = new Gson();
Type type = new TypeToken<MyPojoClass>() {
}.getType();
return gson.fromJson(info, type);
}
This way you'll be able to serialize/deserialize your POJO class without writing a lot of boilerplate. Obviously, you have to annotate your AppDatabase class (the one that extends RoomDatabase) with your Converter using #TypeConverters annotation.
There is a good article about this approach here https://medium.com/#toddcookevt/android-room-storing-lists-of-objects-766cca57e3f9.
Hope that this helps, best luck!
Explore these link to easy understand room persistance database
https://www.youtube.com/watch?v=KAHAQunQkDE
https://developer.android.com/topic/libraries/architecture/adding-components#room
https://developer.android.com/training/data-storage/room/

JsonArray as empty string parsing issue with retrofit

I have a json in which 1 key is coming as jsonArray if it has data otherwise it is coming as empty string. It is giving error while parsing in gson with retrofit.
"section": "Technology",
"subsection": "",
"title": "Depiction of Amazon Stirs a Debate About Work Culture",
"abstract": "Details of working conditions at Amazon led to a response from employees, relatives and friends.",
"url": "http://www.nytimes.com/2015/08/19/technology/amazon-workplace-reactions-comments.html",
"byline": "By THE NEW YORK TIMES",
"item_type": "Article",
"updated_date": "2015-08-18T07:35:33-5:00",
"created_date": "2015-08-18T07:35:35-5:00",
"published_date": "2015-08-19T04:00:00-5:00",
"material_type_facet": "News",
"kicker": "",
"des_facet": [
"Workplace Environment"
],
"org_facet": [
"Amazon.com Inc"
],
"per_facet": "",
"geo_facet": "",
des_facet , org_facet, per_facet, geo_facet are jsonArray but you can see that 2 are not having data so coming as empty string.
How to handle this scenario with retrofit +gson.
Json format can't be changed here at server.
is there any way I can achieve it in android?
Ok so there are two option you can solve this
Option 1:
JSON which I used as a example
"des_facet": [
"Workplace Environment"
],
"org_facet": [
"Amazon.com Inc"
],
"per_facet": ["Akshay"],
"geo_facet": ""
In your model class convert those variable to Object type
#Expose
#SerializedName("geo_facet")
private Object geo_facet;
#Expose
#SerializedName("per_facet")
private Object per_facet;
then where you want to set data do the following
if (model != null)
{
if (model.getGeo_facet() != null || model.getGeo_facet() != "")
{
Object arr = model.getGeo_facet();
}
if (model.getPer_facet() !=null || model.getPer_facet()!= "")
{
Object arr = model.getPer_facet();
if (arr!=null && arr.toString().length()>0)
{
arr = arr.toString();
Log.d("akshay","arr= "+arr);
//Do your Stuff or Set data
}
}
}
This is the output= 08-11 16:51:29.830 17951-17951/com.android.example
D/akshay: arr= [Akshay]
Option 2:
Follow this which is a little bit complex
Option 3:
Write own custom Parsing like this and Handle your response accordingly
a json can have a single structure. From the code it is clear that the key is given with 2 types of data
Ideally, it should not give "" when no items. It should give null
Please change the data
If no items,
"des_facet"=null // this is the change on server side. No need to change it on app side
If it has items
"des_facet"=[
"Workplace Environment"
]
instead of
If no items,
"des_facet"=""
If it has items
"des_facet"=[
"Workplace Environment"
]
You can use AutoValue with gson plugin and mark the field as nullable which will notify the Autovalue to make this field optional.
AZs an example this is how you do it:
#AutoValue
public abstract class NewsResponse{
public static TypeAdapter<NewsResponse> typeAdapter(Gson gson){
return new AutoValue_NewsResponse.GsonTypeAdapter(gson);
}
#SerializedName("api_status")
public abstract String apiStatus();
#SerializedName("api_text")
public abstract String success();
#Nullable
#SerializedName("errors")
public abstract ErrorDetails errorDetails();
#SerializedName("news")
public abstract List<NewsDetails> newsDetails();
}
you must import both of them see more info about importing at: AutoValue and AutoValue Gson Plugin

How to structure a Map from Json that has duplicate keys

Ok so I have this piece of JSON that I want to parse with Gson. I would like the Strings to be the values and the longs to be the keys.
{"completed_questions":[["String",12345],...]}
The issue is the data type, when I try a Map<String, Long> it parses everything but gives me an error because of the duplicate String keys.
I tried to reverse it thinking Gson would know to switch them around but when I tried Map<Long, String> I got an error about not being able to parse my Strings as Longs.
To get it to work I created a swap map class that takes the Key and Value types and swaps them like so public class SwapMap<K, V> implements Map<K, V> however translating the swapped map actions like put/get/remove seem to be pretty difficult to make work.
What's the best way to parse this with Gson even though the strings aren't unique? (But the numbers are)
JSON doesn't allow identical keys on the same level in a json object. It seems like you are trying to map a json array to a java map.
Based on the following data structure, you would need a list if you want to use the default conversion provided by Gson.
{
"completed_questions": [
[
"String",
12345
],
[
"String",
12345
]
]
}
Here is a quick implementation:
private static void mapToObject() {
String json = "{\"completed_questions\":[[\"String\",12345],[\"String\",123456]]}";
Gson gson = new Gson();
CompletedQuestions questions = gson.fromJson(json, CompletedQuestions.class);
for (List<String> arr : questions.getCompleted_questions()) {
for (String val : arr) {
System.out.print(val + " ");
}
System.out.println();
}
}
public static class CompletedQuestions {
List<List<String>> completed_questions;
public List<List<String>> getCompleted_questions() {
return completed_questions;
}
}
This outputs:
String 12345
String 123456
The thing to note is that I am using a list for mapping purposes which closely resembles the data model provided.
This will require you to do the conversion to long yourself. But the way that json string looks. It seems like you would need to operate on the indices. If you have control over the json structure, I would recommending creating a better model. Other wise you can do something like list.get(0) -> your key list.get(1) -> your value which is the long on the inner list.
So what I did is just made a custom Gson Deserializer that mapped these values to a LongSparseArray<String>, which is the best way to go about it.
This is the relevant parts of the Deserializer:
for (JsonElement array : jsonObject.get("my_key").getAsJsonArray()) {
if (array.getAsJsonArray().size() == 2) {
String value = array.getAsJsonArray().get(VALUE).getAsString();
long key = array.getAsJsonArray().get(KEY).getAsLong();
progress.completedActivities.put(key, value);
}
}
Then I just added it to my Gson creator like so:
#Provides #Singleton Gson provideGson() {
return new GsonBuilder()
.registerTypeAdapter(MyClass.class, new MyClass())
.create();
}

JSON tag returns empty array [] while gson expects a string

I am using GSON Library to parse my JSON tag.
some of the tags are expected to hold string values (not arrays). the problem is, sometimes the element is empty [] and when it does that the console gives me this error
expected String but was BEGIIN ARRAY.
The following is the ideal case for my JSON
{
"internet": "600.00",
"internet_remarks": "Fibre 1gbps",
}
but sometimes it becomes
{
"internet": "600.00",
"internet_remarks": [],
}
My parsing code is as follows:
GsonBuilder gsonBuilder = new GsonBuilder();
Gson gson = gsonBuilder.create();
MainContainer mainContainer = gson.fromJson(obj, MainContainer.class);
while in my class is as follows the varailbas are defined as follows
private String internet;
private String internet_remarks;
My question is what changes should i make so that the variable accommodate the empty array []
If you don't control the source of the (poorly designed) JSON and can't fix it, then you're going to need to write a custom deserializer that constructs your MainContainer object.
See: How do I write a custom deserializer? here on SO and/or the information in the Gson User's guide
If the only time that field is an array type is when it's an empty array, the easiest approach I can think of is simply inspecting the returned JSON and if it's an array, remove it. Then deserialize to your MainContainer. Gson silently ignores any missing elements in the JSON and internet_remarks will be null in your MainContainer.
class MyDeserialier implements JsonDeserializer<MainContainer>
{
#Override
public MainContainer deserialize(JsonElement je, Type type,
JsonDeserializationContext jdc)
throws JsonParseException
{
JsonObject obj = je.getAsJsonObject();
if (obj.get("internet_remarks").isJsonArray())
{
obj.remove("internet_remarks");
}
return new Gson().fromJson(obj, MainContainer.class):
}
}
If that's not actually the case and that array might not be empty, you'll need to add the logic to deal with that and convert it to a String if that's what you really want.
In your case:
The gson parser is confused when you are asking it to parse an array into string.
So, you can change the internet_remarks into an array of string.
Its always a safe approach to use annonations in the container class.
Extras:
When ever you are working with json, these two tools will be handy.
1.OnlineJsonEditor.
2.JsonGen
I would suggest declare your second attribute as an array. i.e.
private String[] internet_remarks;
When you have a single string, still put it in the array.
eg:
{
"internet": "600.00",
"internet_remarks": ["Fibre 1gbps"]
}
When it's empty,
{
"internet": "600.00",
"internet_remarks": []
}
So your json will always be consistent.
Also, I noted that you're not really making use of the GsonBuilder. You could just create the Gson instance with a constructor than a builder.
Gson gson = new Gson();

Gson to convert JSON to Object that contain HastMap of Objects?

I have a problem that I have no idea about this, can anyone help me:
Ex we have a json:
{
"status":"0",
"result": {
"object1": {
"name":"name1",
"age":"21"
},
"object2": {
"event":"new year",
"date":"date"
},
"object1_1": {
"name":"name2",
"age":"22"
},
"object2_1": {
"event":"birthday",
"date":"date"
}
}
}
you can try convert to object by using jackson json.
http://jackson.codehaus.org/
If you want to deserialize this json to an object that contains a Map (and the map contains litteral values and other maps). Assuming you have a bean similar to :
class MyBean {
int status;
Map<String, Object> result;
}
MyBean myBean = new Gson().fromJson(jsonString, MyBean.class);
It should work with no modification. Note that if the type of status is not a number I'm not sure Gson does the conversion as in the json string the value is quoted, same thing applies to your "age" property.
You can also have a look at Genson library http://code.google.com/p/genson/ it has most Gson features, other ones that no other library provide and has better performances. Have a look at the wiki http://code.google.com/p/genson/wiki/GettingStarted.
EDIT
Are the names really things like object1_1, object2_1 etc? When looking at the structure I imagine that object1 goes with object2 and so long. If you use gson you can write a custom TypeAdapter http://google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/com/google/gson/TypeAdapter.html.
So you can create a root object similar to
class Response {
int status;
List<MyObject> result;
}
class MyObject {
String name;
int age;
String event;
String date;
}
In the read method of your TypeAdapter you should compose instances of MyObject based on the keys (object1 with object2, object1_1 with object2_1...) or take a similar approach.
If you want more details on how to do that you can also ask on Gson google group.

Categories

Resources