I have to consume a JSON Rest api (for mobile). This api returns a field that is changing like so : (string, int, null, array, object or array of object)
{"field": [{"id": 12, "value": "string value"}]} //array of object
{"field": 12345} //int
{"field": "string"} //string
{"field": {"id": 1, "value": "I'm an object now"}} //object
{"field": ["array", "of", "string"]} //array of string
I may be possible to change the server response to be able to do some standardisation, which could be great! Right now I had to create an adapter (with GSON) but this solution have is limitations, especially with performances and maintainability..
How could I create a good response that will be easy to understand and use?
You could find some relevant information here :
http://jsonapi.org/format/#introduction
https://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api
There isn't any json specifications, everybody can do whatever they want. But there are some best practices.
The simple & useful structure is as below:
{
"success": true,
"message": "It is done",
"data": {
"id": 123,
"value": "string",
"object":{
"object_value":"I'm an object now"
},
"array_object":[ {"key1":"value1"},{"key2":"value2"},{"key3":"value3"} ]
},
"string": "Hello World"
}
Related
I am not that skilled with Retrofit library and I ran into a problem that i don't know how to handle without restructuring the whole project.
Basically, i have two responses that are very similar, but my code only handles one response.
Here are the responses and what i did, so tell me if there is any way to do this...
{
"cv":[
{
"id":46,
"name":"Ciriculum Vitae",
"description":"Lorem ipsum description is the best description one can write down",
"file":"1482915089-test-test-cv1.pdf",
"file_url":"http://xxxyy/file/46/1482915089-test-test-cv1.pdf",
"type":"cv"
},
...
],
"diploma":[
{
"id":52,
"name":"dasdasdasdsa",
"description":"Random description",
"institution_name":"hello",
"completed_date":"12.12.2016.",
"file":"1482918005-test-test-dasdasdasdsa.pdf",
"file_url":"http://xxxyy/file/52/1482918005-test-test-dasdasdasdsa.pdf",
"type":"diploma"
}
],
...
"certification":[
{
"id":50,
"name":"Certificate of Greatness",
"description":"I have been great at many things so everybody diecided to give me a certificate for it.",
"institution_name":"Certification 3",
"validation_date":"10.06.2017.",
"file":"1482917772-test-test-dasdasdasdsa.pdf",
"file_url":"http://xxxyy/file/50/1482917772-test-test-dasdasdasdsa.pdf",
"type":"certification"
}
],
...
}
Okay this is just a sample, but you can clearly see that these are some documents that have their types. There are 17 types of documents each with different fields.
Logically, I've created 17 different models cv model, diploma model, etc...
The problem arises later in the project when i want to fetch documents that are related to a single candidate, the response then is like so:
Response2
"documents": [
{
"id": 46,
"name": "Ciriculum Vitae",
"type": "cv",
"description": "Lorem ipsum description is the best description one can write down",
"file": "1482915089-test-test-cv1.pdf",
"file_url": "http://xxxyy/file/46/1482915089-test-test-cv1.pdf"
},
{
"id":52,
"name":"dasdasdasdsa",
"description":"Random description",
"institution_name":"hello",
"completed_date":"12.12.2016.",
"file":"1482918005-test-test-dasdasdasdsa.pdf",
"file_url":"http://xxxyy/file/52/1482918005-test-test-dasdasdasdsa.pdf",
"type":"diploma"
},
{
"id": 50,
"name": "Certificate of Greatness",
"type": "certification",
"description": "I have been great at many things so everybody diecided to give me a certificate for it.",
"file": "1482917772-test-test-dasdasdasdsa.pdf",
"file_url": "http://xxxyy/file/50/1482917772-test-test-dasdasdasdsa.pdf"
}
]
}
Now obviously the field 'type' is the type of object that needs to be created. But so far i don't know how to make my models fit into this 2nd response.
What should i do here, guys?
In case you're wondering what my code looks like, here it is...
#SerializedName("cv")
#Expose
private List<Cv> cv = null;
...
#SerializedName("diploma")
#Expose
private List<Diploma> diploma = null;
...
#SerializedName("certification")
#Expose
private List<Certification> certification = null;
EDIT
Actually what i wanted to do is create object dependent on the 'type' parameter and fill it with info i get from the response.
How will i go about doing this?
I am parsing a JSON in my activity to display both text and images in a gridView.However i would like to try to add search functionality on this JSON and display the results on the activity.
For example consider a JSON script on an online server like this:
[
{
"title": "Ongata Rongai",
"image": "http://snapt.t15.org/melanie/real_estates/images/house1.jpg",
"rating": 5 500 000,
"releaseYear": 2014,
"genre": ["Spacious open lounge and kitchen"]
},
{
"title": "Kisumu",
"image": "http://snapt.t15.org/melanie/real_estates/images/house2.jpg",
"rating": 1 700 000,
"releaseYear": 2014,
"genre": ["high end townhouse."]
},
{
"title": "Mombasa",
"image": "http://snapt.t15.org/melanie/real_estates/images/house3.jpg",
"rating": 68 000,
"releaseYear": 2014,
"genre": ["Its fully fitted kitchedn pantry with a beautyful backyard."]
}
]
I would like to implement search of title like Kisumu and the result to be displayed will be from this part only so that i parse this alone:
[
{
"title": "Kisumu",
"image": "http://snapt.t15.org/melanie/real_estates/images/house2.jpg",
"rating": 1 700 000,
"releaseYear": 2014,
"genre": ["high end townhouse."]
}
]
Is there a way of achieving the above?
I am open to ideas and suggestions and any help will be appreciated.
You can't search json directly. Convert the json to List Java classes. Then use Java API like Predicate to find necessary java class that satisfy your condition. For eg: Title as Kusumu as you asked.
Which will limit the list of classes to one that satisfy the condition. Then convert the java class back to json if you need Json.
Note: You can use GSON for easy class <-> json conversion
UPDATE
For converting Json to Java classes
List<ModelClass> models = new Gson().fromJson(yourJsonString, ModelClass.java);
Then using predicate
public static Predicate<ModelClass> isHavingTitle() {
return p -> p.getTitle().contains("Kusumu");
}
In Java 8 predicate filtering can be done like below in other case you can just google it. This is a sample
public static List<ModelClass> filterEmployees (List< ModelClass > models, Predicate< ModelClass > predicate) {
return models.stream().filter( predicate ).collect(Collectors.<ModelClass>toList());
}
I didn't compile any of this :)
String filteredJson = new Gson().toJson(models);
this method give resualt of server and title as you want and returns search result as JSONObject
private JSONObject SearchMethod(String result,String Key)
{
//result is your server response
//Key is Kisumu
JSONArray json = new JSONArray(result);
for(int i=0;i<json.length();i++){
JSONObject e = json.getJSONObject(i);
if(e.c.getString("title").contains(Key))
return e ;
}
return null;
}
friends:
I get a response from remote server as follows on Android:
{
"items": {
"persons": [
{
"id": "200120",
"name": "Bill"
},
{
"id": "200121",
"name": "Jim"
}
],
"tasks": [
{
"id": "001",
"name": "Fetch ten books",
"deadline": "5:30 p.m.",
"scores": "10"
},
{
"id": "002",
"name": "Fetch thirty books",
"deadline": "5:30 p.m.",
"scores": "30"
}
],
"intro": "This is a funny game."
},
"otherObj": []
}
And I want to save it to phones. I do not think it a good choice to save it into databases. However it read not fast if put the response to SharedPreferences file. Is there any other way?
No need to save this data into database as these value are dynamic and will change time to time.
In your Activity, call the API and get JSON as response and then parse this JSON and show it on device.
To store it on device u can use Singleton class also.
For JSON parser refer to http://www.tutorialspoint.com/android/android_json_parser.htm
You can first save your data into objects and at last into Object Array and then Save to database.(If your data is dynamic it is better you only deal with Object not database)
For saving to database you can use
db.beginTransaction();
for(object : ObjectArray){
db.dboperation();
}
db.setTransactionSuccessful();
db.endTransaction();
I'm working on porting an iPhone app that relies heavily on JSON to Android.
One of the responses that has to be parsed is used to build the main screen. The JSON response for this contains 3 different objects, namely Icons, Header and Player. These are all contained within the object Home.
Icons and Player both contain an Array of items, the Header is just a single item.
Now I'm still a beginner when it comes to JSON, and I'm not quite sure how I should parse this response. Therefore I would like to know if I have the right idea before working myself into problems.
My idea is to create 4 different classes, one for Home, icons, Header and Player.
Home would contain an array of both Icons and Player, and an object of Header.
But I'm not sure if this is the correct way to do this.
The JSON response in questions is as followed: (Removed some objects due to the size of the response)
{
"Home": {
"Icon": [
{
"ScreenID": 533,
"ScreenIndex": 1,
"IconName": "mainIcon_news",
"Title": "News",
"FK_ModuleID": 6,
"FormID": 567,
"ModName": "News",
"MediaType": "",
"New_Icon": 0
},
{
"ScreenID": 528,
"ScreenIndex": 2,
"IconName": "mainIcon_music",
"Title": "Music",
"FK_ModuleID": 3,
"FormID": 562,
"ModName": "Media",
"MediaType": "Music",
"New_Icon": 0
}
],
"Header": [
{
"ModHomeRotationID": 183,
"image_url": "*****/Media/68/1216_5.jpg",
"flg_RotationEnabled": false,
"flg_RotateOnlyOnReturn": true,
"flg_RotationRandomize": false,
"flg_RotationDelayMS": 5000,
"flg_RotationDelayFadeMS": 3000,
"HomeRotationIndex": null
}
],
"Player": [
{
"MediaID": 1219,
"Track_Name": "***",
"song_url": "*****/Media/68/1219.mp3",
"song_remote_url": null,
"FileSize": 4700502
},
{
"MediaID": 1220,
"Track_Name": "**** ",
"song_url": "*****/Media/68/1220.mp3",
"song_remote_url": null,
"FileSize": 4350222
}
]
}
}
Could someone tell me if I'm in the right direction, and if not, what I should be doing instead?
I should mention, I'm using GSON to parse the JSON responses at the moment.
Thanks in advance
Yes you are right you need to create Four classes and need to initialize the values inside that class name..
Validate your Json using JSONLint :
Then try this sample Parsing JSON using GSON and One More
I need to parse a JSON response regarding events in an agenda, of which a field is dynamic. This field changes depending on the month in which the event takes place.
Now I've been parsing data with GSON before, but these all had static fields so it was quite easy to create the necessary POJO's. But how would I do this with dynamic fields?
The response i need to parse is like so:
{
"Agenda/Future": {
"November 2011/0": [
{
"id": "5675",
"eventid": "",
"name": "testing testing 123",
"startdate": "nov 25",
"datecompute": "2011-11-25T08:00:00",
"group_month": "November 2011",
"flg_Data": "Database"
}
],
"February 2012/1": [
{
"id": "5681",
"eventid": "",
"name": "dfd",
"startdate": "feb 3",
"datecompute": "2012-02-03T12:00:00",
"group_month": "February 2012",
"flg_Data": "Database"
},
{
"id": "5679",
"eventid": "",
"name": "vfvd",
"startdate": "feb 17",
"datecompute": "2012-02-17T12:00:00",
"group_month": "February 2012",
"flg_Data": "Database"
}
],
"February 2013/2": [
{
"id": "5680",
"eventid": "",
"name": "df",
"startdate": "feb 14",
"datecompute": "2013-02-14T12:00:00",
"group_month": "February 2013",
"flg_Data": "Database"
}
],
"September 2013/3": [
{
"id": "5677",
"eventid": "",
"name": "fsdfsd",
"startdate": "sep 14",
"datecompute": "2013-09-14T12:00:00",
"group_month": "September 2013",
"flg_Data": "Database"
}
],
"November 2015/4": [
{
"id": "5676",
"eventid": "",
"name": "fsdfsd",
"startdate": "nov 13",
"datecompute": "2015-11-13T12:00:00",
"group_month": "November 2015",
"flg_Data": "Database"
}
]
}
}
As you can see, the object title regarding months is dynamic. Both the value at the end of the title, as well as the title itself change based on the actual month and position in the array of months.
From what I've seen on other questions here at SO, I will need to work with Maps.
But I'm not quite sure how I would go about doing so.
Let's say I create a POJO called Event for the individual events contained in the array of the months, what would my initialization look like?
Regards
I have tried Amir's suggestion by using Jackson with the default Map.
Sadly, this creates a Map with a size of 1. The entire JSON response gets parsed into a single object. Ofcourse, this is not what I want, since I need to get the data from the individual events.
Does anyone have a suggestion as to how I might be able to do that? Normally I'd figure out these things quite quickly but I can't wrap my head around this one due to the dynamic object naming.
I have eventually managed to crack this problem. I ended up using plain JSONObjects, which worked eventually.
The code I used to get it to work is as follows:
JSONObject jsonObject = new JSONObject(response);
JSONObject agenda = jsonObject.getJSONObject("Agenda/Future");
if (agenda != null) {
System.out.println(agenda.length());
JSONArray events = agenda.names();
if (events.length() > 0) {
System.out.println("At least its bigger then 0. It's: "
+ events.length());
for (int i = 0; i < events.length(); i++) {
System.out.println(events.get(i).toString());
JSONArray test = agenda.getJSONArray(events.get(i)
.toString());
if (test != null) {
JSONObject testt = test.getJSONObject(0);
if (testt != null) {
System.out.println(testt.getString("name"));
} else {
System.out.println("Still empty, Check again.");
}
}
}
}
} else {
System.out.println("Agenda is completely empty, try again.");
}
As you can see, this still contains test-names, but at least it works.
Thanks for the help everyone!
Since the month data are not valid java identifiers, you 'll probably have to use custom serialization with GSON. You're talking about using Map objects but if you are going to do that you may as well us the org.json objects like JSONObject which are basically built on maps/hashtables anyway.
If all your fields, as you have said, are dynamic then you can create a super set of all fields in a pojo. But that doesn't really help and I think the Map is the best solution. With GSON, you can do
Type type = new TypeToken<Map<String, String>>(){}.getType();
Map<String, String> map = gson.fromJson("{'key1':'123','key2':'456'}", type);
This will return a map of strings.
I haven't actually used GSON to do this before though. I have been very happy with Jackson lib and with that you can do
new ObjectMapper().readValue("...json...", Map.class)
The above will return a map of maps which is what you want.