JSON parsing using GSON - Setting up class hierarchy - android

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.

Related

Need to post JSON as an array of objects via Retrofit while dynamically adding objects

I have to post a JSON Array of objects. The JSON sample is pasted below:
[
{
"checklistkey": "what is your age ___ and ur bd___",
"checklistvalue": "yes",
"taskId": "PMTASK-cmms-01-71-1"
},
{
"checklistkey": "how r you___? ______",
"checklistvalue": "no",
"taskId": "PMTASK-cmms-DE01-71-1"
}
]
The number of object here will be added dynamically based on the ID received in the previous request.
Now the POJO for this looks like:
public class CheckListAddRequest {
#SerializedName("taskId")
#Expose
private String taskId;
#SerializedName("checklistkey")
#Expose
private String checklistkey;
#SerializedName("checklistvalue")
#Expose
private String checklistvalue;
public String getTaskId() {
return taskId;
}
public void setTaskId(String taskId) {
this.taskId = taskId;
}
public String getChecklistkey() {
return checklistkey;
}
public void setChecklistkey(String checklistkey) {
this.checklistkey = checklistkey;
}
public String getChecklistvalue() {
return checklistvalue;
}
public void setChecklistvalue(String checklistvalue) {
this.checklistvalue = checklistvalue;
}
public CheckListAddRequest(String taskId, String checklistkey, String checklistvalue) {
this.taskId = taskId;
this.checklistkey = checklistkey;
this.checklistvalue = checklistvalue;
}}
The Retrofit call for this is:
#POST("cmms")
#Headers("Content-Type: application/json")
Call<CheckListAddResponse> getCheckListAdd(#Body CheckListAddRequest checkListAddRequest,
#Header("X-Auth-Token") String token,
#Header("workspace") String workspace);
Now while added the details for creating a JSON request, I write something like:
CheckListAddRequest checkListAddRequest = new CheckListAddRequest(taskNumber, checkDesc, statusString);
Now if I have more than one object in the request, how can I send it?
This should be an array/list if its multiple and dynamic objects, you can easily change items add or remove from List and send
ArrayList< CheckListAddRequest >.
make this minor change.
#POST("cmms")
#Headers("Content-Type: application/json")
Call<CheckListAddResponse> getCheckListAdd(#Body ArrayList<CheckListAddRequest> checkListAddRequest,
#Header("X-Auth-Token") String token,
#Header("workspace") String workspace);
now pass the value in array list or list.

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.

From JSon array to custom data structure

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());
}

How to save retrofit array to sqlite database?

here is my jsonString:
{
"status":1,
"data":[
{
"id":"39",
"friendsInfo":{
"email":"test#gmail.com",
"phone":null,
"language":"en"
}
},
{
"id":"39",
"friendsInfo":{
"email":"test#gmail.com",
"phone":null,
"language":"en"
}
}
],
"message":""
}
here is my receivingClass:
public class mAnswer{
#SerializedName("status")
public int mEnterStatus;
#SerializedName("data")
public List<Data> dataList;
public class Data {
#SerializedName("id")
public int mUserId;
#SerializedName("friendsInfo")
public GetUserDetails getUserDetails;
public class GetUserDetails{
#SerializedName("email")
public int email;
#SerializedName("phone")
public String phone;
#SerializedName("language")
public String language;
}
}
}
and here is my code for successful receiving answer where I am trying to save this data to SQLite db:
private void saveList(){
Vector<ContentValues> cVVector = new Vector<ContentValues>();
int arraySize = mAnswer.dataList.size();
for (int i = 0; i < arraySize; i++){
// **HERE IS PROBLEM**
cVVector.add(friendsValue);
}
if (arraySize > 0 ){
ContentValues[] cvArray = new ContentValues[arraySize];
cVVector.toArray(cvArray);
mContext.getContentResolver().
bulkInsert(J4D_DB_Contract.UserFriendsEntry.CONTENT_URI, cvArray);
}
}
So here is my problem:
how to correct call #SerializedName elements when i am trying to save List data to db?
any ideas?
Will be glad any help! Thanks!
mAnswer.dataList.get(0);
gives back the
"id":"39",
"friendsInfo":{
"email":"test#gmail.com",
"phone":null,
"language":"en"
}
this is what you should say in the loop:
mAnswer.dataList.get(0).getFriendsObject().getEmail();
mAnswer.dataList.get(0).getFriendsObject().getPhone();
I would use this site to generate my POJO, beucase it`s more cleaner I think.
http://www.jsonschema2pojo.org/
This site gives back well defined POJO architecture, what is ready for use.
Just set that you are working with JSON instead of JSON Scheme and using GSON (if you are using retrofit).
After you can copy your java files to your workplace.
You don't need the #SerializedName("jsonName") if the variable has the same name private String jsonName;

How to get timestamp(rowversion) from sql azure to android with mobileservice

i have a problem getting timestamp(rowversion) from my SQL Azure database.
In my tables there is a column with datatype timestamp. This timestamp isn't similar to datetime, it's more like a rowversion.
I can get all other data in this table with the query from MobileServiceTable, there is no problem.
But this special datatype is a problem.
My class for this table looks like:
public class ArbeitsgangBezeichnung {
#com.google.gson.annotations.SerializedName("id")
private int ID;
#com.google.gson.annotations.SerializedName("ABZ_ArbeitsgangBezeichnungID")
private int ABZ_ArbeitsgangBezeichnungID;
#com.google.gson.annotations.SerializedName("ABZ_Bezeichnung")
private String ABZ_Bezeichnung;
#com.google.gson.annotations.SerializedName("ABZ_RowVersion")
private StringMap<Number> ABZ_RowVersion;
//constructor, getter, setter, etc....
}
If i login in Azure and look at the table, there are my example values and the automatic generated timestamp. The timestamp value looks like "AAAAAAAAB/M=". If i login in sql database and let me show the data, then for timestamp there is only "binarydata" (in pointed brackets) and not that value as it is shown in Azure.
The variable "ABZ_RowVersion" should include this timestamp, but the data in the StringMap doesn't look like the one in Azure. I tried String and Byte as datatype for the StringMap, but it doesn't helped.
I tried byte[] for ABZ_RowVersion, but then i got an exception in the callback method.
Then i tried Object for ABZ_RowVersion, that time i found out, that it is a StringMap, but nothing more.
Does anybody know, how to get the data from timestamp, i need it for comparison.
Thanks already
When you create a timestamp column in a table, it's essentially a varbinary(8) column. In the node SQL driver, it's mapped to a Buffer type (the usual node.js type used for binary data). The object which you see ({"0":0, "1":0, ..., "length":8}) is the way that a buffer is stringified into JSON. That representation doesn't map to the default byte array representation from the Gson serializer in Android (or to the byte[] in the managed code).
To be able to use timestamp columns, the first thing you need to do is to "teach" the serializer how to understand the format of the column returned by the server. You can do that with a JsonDeserializer<byte[]> class:
public class ByteArrayFromNodeBufferGsonSerializer
implements JsonDeserializer<byte[]> {
#Override
public byte[] deserialize(JsonElement element, Type type,
JsonDeserializationContext context) throws JsonParseException {
if (element == null || element.isJsonNull()) {
return null;
} else {
JsonObject jo = element.getAsJsonObject();
int len = jo.get("length").getAsInt();
byte[] result = new byte[len];
for (int i = 0; i < len; i++) {
String key = Integer.toString(i);
result[i] = jo.get(key).getAsByte();
}
return result;
}
}
}
Now you should be able to read data. There's still another problem, though. On insert and update operations, the value of the column is sent by the client, and SQL doesn't let you set them in them. So let's take this class:
public class Test {
#SerializedName("id")
private int mId;
#SerializedName("name")
private String mName;
#SerializedName("version")
private byte[] mVersion;
public int getId() { return mId; }
public void setId(int id) { this.mId = id; }
public String getName() { return mName; }
public void setName(String name) { this.mName = name; }
public byte[] getVersion() { return mVersion; }
public void setVersion(byte[] version) { this.mVersion = version; }
}
On the insert and update operations, the first thing we need to do in the server-side script is to remove that property from the object. And there's another issue: after the insert is done, the runtime doesn't return the rowversion property (i.e., it doesn't update the item variable. So we need to perform a lookup against the DB to retrieve that column as well:
function insert(item, user, request) {
delete item.version;
request.execute({
success: function() {
tables.current.lookup(item.id, {
success: function(inserted) {
request.respond(201, inserted);
}
});
}
});
}
And the same on update:
function update(item, user, request) {
delete item.version;
request.execute({
success: function() {
tables.current.lookup(item.id, {
success: function(updated) {
request.respond(200, updated);
}
});
}
});
}
Now, this definitely is a lot of work - the support for this type of column should be better. I've created a feature request in the UserVoice page at http://mobileservices.uservoice.com/forums/182281-feature-requests/suggestions/4670504-better-support-for-timestamp-columns, so feel free to vote it up to help the team prioritize it.

Categories

Resources