Android Retrofit and bad data contract - android

Normally RESTful end point returns one object or a list of said type object with some additional data for pagination purposes.
However, interesting case, the API I am working with will return a list of mixed type objects. For example:
{
"media": [
{
"id": 1,
"type": "oranges",
"Some type specific property": "foo"
},
{
"id": 1,
"type": "apples",
"Some type specific property": "bar"
}
]
}
Is it possible for retrofit to accommodate this with reflection and properly pick out the different type of objects returned with the same key? (As in our example media)
The mobile application is already running in production mode, and what would be the least painful way to accommodate this API architecture?

use http://www.jsonschema2pojo.org/ to create java object models
define your api using retrofit
public interface sampleApi {
#GET("/v1/endpoint")
void promoImages(Callback<CustomObject> callback);
Create Adapter
RestAdapter.Builder builder = new RestAdapter.Builder()
.setEndpoint(BuildConfig.BASE_SERVER_ENDPOINT)
.setClient(new OkClient(client));
CustomApi api = builder.build().create(CustomApi.class);
Call api
api.promoImages(callback);

Related

Retrofit Dynamic JSON response

I'm new to JSON handling with retrofit but I've run into a problem.
We're making a prototype smart assistant chatbot with Dialogflow.
My Android Client sends a POST request to Google Dialogflow, which will call third party API's and send a response back.
However, this response depends on the type of intent detected by Dialogflow.
It can be nearly everything from music to weather information etc.
So the parameters (for the visualization) will be completely different and I don't know the type of response in advance.
I preprocess the response from Dialogflow in my own cloud function and send it back containing only the necessary fields for the client.
For example:
"What is the weather today in Brussels?"
Response:
{
"sessionId": "123456789",
"keepAlive": true,
"intentId": 100,
"intentName": "Weer",
"text": "Het weer in Hanoi is helder met een temperatuur van 23.2 graden.",
"Parameters": {
"text": {
"stringValue": "helder",
"kind": "stringValue"
},
"city": {
"stringValue": "Hanoi",
"kind": "stringValue"
},
"temp": {
"numberValue": 23.2,
"kind": "numberValue"
},
"intentId": {
"numberValue": 100,
"kind": "numberValue"
}
}
}
You can see the Parameters of the response depend on the type of intent(id). there can be many or zero parameters depending on the intent.
How can I make a Pojo for every type of response, not only the weather?
Or can I make a switch case based on intentId or something?
You can use generics than
public class Response<T> {
private String responseId;
private String sessionId;
private boolean keepAlive;
private float intentId;
private String intentName;
private String text;
private String Audio;
private T Parameters;
}
and when you want to create the object you can
new Response<YourClass>();
Your class will be the class as per your intent id

what is the equivalent to newsoft json in android

i have problems i am searching and cant understand what type of json parser i can use for example i have local json and i want to prase it is there any sdk i can use near the newsoft json or ez to learn because i am windows phone and 8.1 developer and i sucks with android and i really need it for graduation project i created almost every thing
[
{
"id": 1,
"time": 40,
"srcLong": 35.909124,
"srcLat": 31.973628,
"destLong": 35.898258,
"destLat": 31.985622,
"subSites": [
{
"id": 1,
"name": "location 1"
},
{
"id": 2,
"name": "location 2"
},
{
"id": 3,
"name": "location 3"
}
]
}]
plz how to get the response for example the code in newsoft json is like this
var serviceUri = "http://localhost:24728/api/sites";
HttpClient client = new HttpClient();
var response = await client.GetAsync(serviceUri);
var datafile = await response.Content.ReadAsStringAsync();
RootObject data = JsonConvert.DeserializeObject<RootObject (((string)datafile).Substring(1, ((string)datafile).Length - 2));
and of course you create the class to deal with object plz can some one help me with this and i need to remove the [] to be json object i just need the sdk i should use and where to start learn and if there no problem to tell me how to substring it and to put this code
string uri = "http://localhost:24728/api/sites/1";
HttpResponseMessage response2 = await client.PutAsJsonAsync(uri, data);
plz is there any equivalent in android.
Regards,
Ayesh.
Well from what you are saying it looks like you are unsure of how to get a response from the site, maybe you do not understand how to access the url initially. Or potentially that once you get the response and it is prehaps a string you do not know how to convert it into JSON to extract the information. Send information from android application to a Web Service and back. This link has a basic version of connecting to a url. And when you have a string, you can use JSONObject and JSONArrays to grab the information on that string, you can do JSONArray(string).

Retrofit doesn't recognize nested json response

I'm using Retrofit to get json response. I also generated model classes with http://www.jsonschema2pojo.org/ However it doesn't work. The problem is json response doesn't fit to my java object. Am I miss something?
{
"status":"ok",
"status_message":"Query was successful",
"data":{
"movie_count":1,
"limit":20,
"page_number":1,
"movies":[
{
"id":4281,
"url":"https:\/\/yts.to\/movie\/the-third-man-1949",
"imdb_code":"tt0041959",
"title":"The Third Man",
"title_long":"The Third Man (1949)",
"slug":"the-third-man-1949",
"year":1949,
"rating":8.3,
"runtime":93,
"genres":[
"Film-Noir",
"Mystery"
],
"language":"English",
"mpa_rating":"Not Rated",
"background_image":"https:\/\/s.ynet.io\/assets\/images\/movies\/the_third_man_1949\/background.jpg",
"small_cover_image":"https:\/\/s.ynet.io\/assets\/images\/movies\/the_third_man_1949\/small-cover.jpg",
"medium_cover_image":"https:\/\/s.ynet.io\/assets\/images\/movies\/the_third_man_1949\/medium-cover.jpg",
"state":"ok",
"date_uploaded":"2015-07-13 10:22:11",
"date_uploaded_unix":1436739731
},
]
},
"#meta":{
"server_time":1436799207,
"server_timezone":"Pacific\/Auckland",
"api_version":2,
"execution_time":"34.67 ms"
}
}
There's a problem at line number 31 where you put a comma(,) after the 2nd bracket { . Remove the comma and everything is fine .

How to build JSON Request Body?

I'm trying to build the following JSON Request Body.
It's my first time with JSON and I'm following this examples, but still struggling.
I've been taking a look to GSON but wanted to manage pure JSON first, and maybe for something so small it's not worth it to add GSON library?
Could you help me with the code?
Thanks.
{
locations:
[
{
latLng:
{
lat: 40.900799,
lng: 8.606102
}
},
{
latLng:
{
lat: 42.900799,
lng: 9.606102
}
}
]
}
EDIT:
Here is the Web Service I am trying to consume and here a request sample.
Use json objects.
Do something like that.
Don't write json by hand, you could easily do a mistake.
public JSON() throws JSONException
{
JSONArray locArr=new JSONArray();
locArr.put(createLatLng(40.900799, 8.606102));
locArr.put(createLatLng(42.900799, 9.606102));
JSONObject main=new JSONObject();
main.put("locations", locArr);
Log.d("JSON",main.toString());
}
public JSONObject createLatLng(double lat, double lng) throws JSONException
{
JSONObject latLng=new JSONObject();
latLng.put("lat",lat);
latLng.put("lon",lng);
JSONObject latLngWrap=new JSONObject();
latLngWrap.put("latLng",latLng);
return latLngWrap;
}
JSON notation requires the "" around field names. Values should only be wrapped, if they are string.
{
"locations":
[
{
"latLng":
{
"lat": 40.900799,
"lng": 8.606102
}
},
{
"latLng":
{
"lat": 42.900799,
"lng": 9.606102
}
}
]
}
You can always verify, if you JSON is correct using
http://jsonlint.com/
Expanding on maciekczwa's answer. JSON (unlike arguably XML) isn't really meant to be looked at with human eyes. It very quickly becomes very hard to see where one object starts and ends and what's wrapping what. Use his example to create your main JSON object and then fill it with whatever objects you need to. When you're all done you can convert it to string for transport very easily, without having to look at it, and doing it this way means not having to worry about what labels need to be wrapped in what kinds of quotes etc.
And eskalera is 100% correct. JSON requires all fields to be wrapped in quotes (the rules around whether or not they can be single quotes or *MUST be double quotes vary from implementation to implementation, but again, this is only relevant if you're constructing the JSON manually, as you should only do in instances where it's EXTREMELY simple (and even then... probably not).

Using JSON to create an object in Groovy/Grails

I have a Groovy/Grails website that is being used to send data to Android clients via JSON. I have created both the Android client and the Groovy/Grails website; and they can output the same objects in JSON.
I can successfully create the respective objects in Android by mapping the JSON output to Java objects, however I was wondering if it's possible to use the JSON output to create a new domain object in Groovy/Grails? Is there a way of passing the JSON output to a controller action so that object will be created?
Here is an example of the JSON that I'd like to send;
{
"class":"org.icc.callrz.BusinessCard.BusinessCard",
"id":1,
"businessCardDesigns":[],
"emailAddrs":[
{
"class":"org.icc.callrz.BusinessCard.EmailAddress",
"id":1,
"address":"chris#krslynx.com",
"businessCard":{
"_ref":"../..",
"class":"org.icc.callrz.BusinessCard.BusinessCard"
},
"index":0,
"type":{
"enumType":"org.icc.callrz.BusinessCard.EmailAddress$EmailAddressType",
"name":"H"
}
},
{
"class":"org.icc.callrz.BusinessCard.EmailAddress",
"id":2,
"address":"cb#i-cc.cc",
"businessCard":{
"_ref":"../..",
"class":"org.icc.callrz.BusinessCard.BusinessCard"
},
"index":1,
"type":{
"enumType":"org.icc.callrz.BusinessCard.EmailAddress$EmailAddressType",
"name":"W"
}
}
]
}
The "class" matches to the Domain I'd like to save to, the ID is the ID of the Domain, then each item within the businessCardDesigns and emailAddrs needs to be saved using similar methods (in the Domain the businessCardDesigns and emailAddrs are ArrayLists). Many thanks in advance!
SOLUTION:
#RequestMapping(method = RequestMethod.POST, headers = "Accept=application/json")
public ResponseEntity<String> createFromJson(#RequestBody String json) {
Owner.fromJsonToOwner(json).persist();
return new ResponseEntity<String>(HttpStatus.CREATED);
}
Using the built-in Grails JSON converter makes this easier than the other answers, in my opinion:
import grails.converters.JSON
class PersonController {
def save = {
def person = new Person(JSON.parse(params.person))
person.save(flush:true)
}
}
The other benefits are:
There's no need to muck around in any config files
The resulting JSON object can be manipulated, if necessary, before assigning properties
It's far clearer in the code what's happening (we're parsing a JSON object and setting the properties on the Person entity)
I know you already accepted an answer but if I'm reading your question right, there's a built in "Grails" way to do this.
Create an entry for your action in URLMappings.groovy and turn on request parsing. For example, I create RESTful mappings like so:
"/api/bizCard/save"(controller: "businessCard", parseRequest: true) {
action = [POST: "save"]
}
And then in you controller
def save = {
def businessCardInstance = new BusinessCard(params.businessCard)
....
businessCardInstance.save(flush:true)
}
this might work for you
http://static.springsource.org/spring-roo/reference/html/base-json.html

Categories

Resources