From JSon array to custom data structure - android

Say I need to fill a Binary Search Tree with data obtained from Server. Say further that the data coming from server is a json array of nodes
"parts":[{"id":1,"name":"apple"},{"id":12,"name":"orange"},{"id":21,"name":"pen"},{"id":214,"name":"kite"}]//where each {} represents a node
How do I use GSon to read the array of Nodes into my BST?
If you recall a BST has two classes
public class BST{
private Note root;
}
public class Node{
String el;
Node left, right;
}
If BST is too hard, image something simpler
public class MyDataStructure{
private List<Part> partsList;
…
}
public class Part{
String el;
List<String> stuff;
}
How do I populate MyDataStructure with partsList using GSon on android? As a side note, I would rather help solving the MyDataStruction version of the problem.

ok.. you can use this as reference:
define a class pojo
and a Fruit(is the array/list/collection)
the pojo
class Pojo {
#Override
public String toString() {
return "Pojo [parts=" + parts + "]";
}
private List<Fruits> parts;
}
the fruit
class Fruits {
private int id;
private String name;
#Override
public String toString() {
return "[id=" + id + ", name=" + name + "]";
}
}
the implementation
String json = "{\"parts\": [{\"id\":1,\"name\":\"apple\"},{\"id\":2,\"name\":\"pear\"},{\"id\":3,\"name\":\"kiwi\"}]}";
Gson g = new Gson();
Pojo p = g.fromJson(json, Pojo.class);
System.out.println(p);
the MyDataStructure population
add to the pojo a setter getter so you can work with the list, add too setter and getter for the fruit class so you can get the id and the name..
so in the pojo object p you can do p.getList() and iterate over the elements
Something like:
Pojo p = g.fromJson(json, Pojo.class);
System.out.println(p);
for (Fruits f : p.getParts()) {
System.out.println(f.getId());
System.out.println(f.getName());
}

Related

Parsing and saving a nested JSON into SQLite, and then retrieving it

Edit
I managed to insert only the outer JSON object. Couldn't find information on how to insert nested objects. Each object has primitive fields in it. These objects can be seen in the JSON sample below: "languages" and "currencies". I also wonder how to deal with the "latlng" array within the outer JSON object, but it's probably better to handle these issues one at a time.
The code I got for inserting a primitive value in the outer JSON object:
Gson gson = new Gson();
Type listType = new TypeToken<List<Country>>(){}.getType();
List<Country> countriesList = gson.fromJson(jsonString, listType);
for(Country country : countriesList) {
ContentValues insertValues = new ContentValues();
insertValues.put(Country.NAME, country.getName());
//more insertions
}
The original question
I parsed a nested JSON with GSON (probably incorrectly since it's my first time). Now I'm trying to insert it to SQLite. Couldn't find what needs to be written next. When I write the for loop for the insertion I get the error cannot find symbol class Country. Couldn't find relevant guidance online so I hope anyone can help in how to move forward.
That's where the issue begins:
Country[] countriesArray = gson.fromJson(jsonString, Country[].class);
for (int i = 0; i < countriesArray.length(); i++) {
...
}
countriesArray.length() is marked as an error: cannot find symbol class Country.
One object from the JSON:
[
{
"name":"Afghanistan",
"topLevelDomain":[
".af"
],
"callingCodes":[
"93"
],
"capital":"Kabul",
"region":"Asia",
"subregion":"Southern Asia",
"population":27657145,
"latlng":[
33.0,
65.0
],
"demonym":"Afghan",
"area":652230.0,
"gini":27.8,
"timezones":[
"UTC+04:30"
],
"nativeName":"افغانستان",
"numericCode":"004",
"currencies":[
{
"name":"Afghan afghani",
"symbol":"؋"
}
],
"languages":[
{
"name":"Pashto",
"nativeName":"پښتو"
},
{
"name":"Uzbek",
"nativeName":"Oʻzbek"
},
{
"name":"Turkmen",
"nativeName":"Türkmen"
}
],
"translations":{
"de":"Afghanistan",
},
"flag":"https://restcountries.eu/data/afg.svg",
"cioc":"AFG"
},
The model classes I wrote are only for the variables objects and arrays I needed.
The model class Country.Java
public class Country implements Parcelable {
private String name;
private String capital;
private String region;
private String subregion;
private int population;
private List<Double> latlng = new ArrayList<Double>();
private double area;
private double gini;
private List<String> timezones = new ArrayList<String>();
private List<Currency> currencies = new ArrayList<Currency>();
private List<Language> languages = new ArrayList<Language>();
private String flag;
public Country() {}
//getters, setters, toString() and Parcelable methods
}
The model class Currency.Java
public class Currency implements Parcelable {
private String name;
private String symbol;
//getters, setters, toString() and Parcelable methods
}
The model class Language.Java
public class Language implements Parcelable {
private String name;
private String nativeName;
//getters, setters, toString() and Parcelable methods
}
Create a typeToken and pass it to fromJson method like following
Type listType = new TypeToken<List<Country>>(){}.getType();
List<Country> countryList = gson.fromJson(jsonArray.toString(), listType);
Use Gson TypeToken to set the return object type during JSON parse
List<Country> countries = gson.fromJson(jsonString, new TypeToken<List<Country>>(){}.getType());
for(Country country : countries) {
//Do your DB operation here
}

How do you parse json object inside a json array?

I am pretty weak with JSON, and probably have a silly question, and was wondering how to parse a JSON object placed inside a JSON array.
So, as of now, I have
public Single<Profile> doProfileApiCall() {
return Rx2AndroidNetworking.post(ApiEndPoint.ENDPOINT_PROFILE)
.addHeaders(mApiHeader.getProtectedApiHeader())
.build()
.getObjectSingle(Profile.class);
To retrieve my profile params, but in my endpoints I have :
[{"Name": "this", "Email","that#gmail.com"}]
I have my endpoint set up as :
public static final String ENDPOINT_PROFILE =
BuildConfig.BASE_URL
+ "/linktojson";
which gives me the above JSON.
but the issue is the [], how do I modify this with :
public Single<Profile> doProfileApiCall() {
return Rx2AndroidNetworking.post(ApiEndPoint.ENDPOINT_PROFILE)
.addHeaders(mApiHeader.getProtectedApiHeader())
.build()
.getObjectSingle(Profile.class);
such that I can use my profile.java model class which has
public class Profile {
#Expose
#SerializedName("Name")
private String name;
#Expose
#SerializedName("Email")
private String email;
etc...
}
Any idea how to go about this?
In the doProfileApiCall() method instead of .getObjectSingle use
.getJSONArraySingle(ProfileList.class)
Now create a new class ProfileList.java with the following code.
List<Profile> profileList = new ArrayList<>();
public List<Profile> getProfileList() {
return profileList;
}
public void setProfileList(List<Profile> profileList) {
this.profileList = profileList;
}
Change the returntype of the doProfileApiCall method to
public Single<ProfileList> doProfileApiCall()
Whenever you want to access the data use it with the list position 0, when in future you get more data, you can index the data accordingly.
Generally, if JSON root object is an array you should use List on Java side. In your case you have array so use related method:
return Rx2AndroidNetworking.post(ApiEndPoint.ENDPOINT_PROFILE)
.addHeaders(mApiHeader.getProtectedApiHeader())
.build()
.getObjectListSingle(Profile.class);
Rx2ANRequest source.

Gson make firebase-like json from objects

In the past a manually created as list of data, which was stored locally in a database. Now I would like to parse those data and put them through import json option into firebase dbs, but what I get doesn't look like firebase generated json.
What I get is:
[
{
"id":"id_1",
"text":"some text"
},
{
"id":"id_2",
"text":"some text2"
},
...
]
what I want is something like this:
{
"id_1": {
"text":"some text",
"id":"id_1"
},
"id_2":{
"text":"some text2",
"id":"id_1"
},
...
}
my Card class
class Card{
private String id;
private String text;
}
retrieving data
//return list of card
List<Card> cards =myDatabase.retrieveData();
Gson gson = new Gson();
String data = gson.toJson(cards);
So how I can I achieve this (it looks to me) dynamically named properties for json that look like those generated by firebase ?
EDIT:
I found that gson has FieldNamingStrategy interface that can change names of fields. But it looks to me it's not dynamic as I want.
EDIT2
my temp fix was to just override toString()
#Override
public String toString() {
return "\""+id+"\": {" +
"\"text\":" + "\""+text+"\","+
"\"id\":" +"\""+ id +"\","+
"\"type\":"+ "\""+ type +"\""+
'}';
}
Your "temp fix" will store each object as a string not a object.
You need to serialize an object to get that data, not a list.
For example, using a Map
List<Card> cards = myDatabase.retrieveData();
Map<Map<String, Object>> fireMap = new TreeMap<>();
int i = 1;
for (Card c : cards) {
Map<String, Object> cardMap = new TreeMap<>();
cardMap.put("text", c.getText());
fireMap.put("id_" + (i++), cardMap);
}
Gson gson = new Gson();
String data = gson.toJson(fireMap);

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

JSON parsing using GSON - Setting up class hierarchy

I can't seem to wrap my head around how to setup my class hierarchy for JSON conversion using GSON.
My JSON looks like:
{
"Users": {
"id": 1,
"name": "Jim",
"location": "Huntsville"
}
}
My User List class looks like:
public class UserList {
public static List<User> Users;
#SuppressWarnings("static-access")
public void setUserList(List<User> userList){
this.Users = userList;
}
public List<User> getUserList(){
return Users;
}
}
and lastly a user class that looks like this:
public class User {
private int id;
private String name;
private String location;
public int getId(){
return id;
}
public String getName(){
return name;
}
public String getLocation(){
return location;
}
public String toString(){
return("User: [id=" + id + "], [name=" + name + "], [location=" + location + "]");
}
}
Anyone mind giving me a shove in the right direction? I'd appreciate it!
EDIT:
Forgot to show my parsing code.. (Just reading a sample JSON file from SDCard)
BufferedReader br = new BufferedReader(new FileReader(Environment.getExternalStorageDirectory() + "/user.json"));
UserList userList = gson.fromJson(br, UserList.class);
are you sure your example JSON is correct?
It does not seem to be a list of things, just one user is defined.
Furthermore, your getter and setters for Users, should be following the get/set pattern and be called
public List<User> getUsers()
public void setUsers(List<User> users)
Also, you can follow the Java convention of small case and instruct Gson to use a different casing.
Assuming that you only have one entry of Users in your JSON. This would let you parse the snippit you provided, if you change the Users property into User not a list.
#SerializedName("Users")
private User user;
So if you want a list of users you should find that in the json, this should let you parse it as a list, !note that you need to have objects, which are enclosed, like:
{"users" : [{id:"one"}, ...]}
As pointed out in the comments.

Categories

Resources