Retrofit and Generics and Inconsistent API data - android

From Retrofit's documentation:
RESPONSE OBJECT TYPE
HTTP responses are automatically converted to a specified type using the RestAdapter's converter which defaults to JSON. The desired type is declared as the method return type or using the Callback or Observable.
#GET("/users/list")
List<User> userList();
Retrofit will automatically convert a returned response (JSON, XML, etc) into the desired object that is specified by the method.
In the documentation's case, it will return a List of User objects.
How can one interface retrofit with a badly designed API that returns a list of different typed objects.
The psudocode will look something like:
#GET("/users/list")
List<User|Pet> userList();
Edit: The API returns a mix of the two types together. There are no flags or switches to change that.
Example /users/list:
{
"data": [
{
"animal": "dog",
"speak": "woof"
},
{
"username": "Bob",
"age": 30
}
]
}

Related

How to convert unstructured JSON to POJO using Moshi and Retrofit

I came across one issue with some of the response we getting is not straight to parse and convert it to POJO. The format of response I am getting is as below
[
"list",
[
{
"#type": "com.exampe.model.ModelName",
"number": 1,
"name": "Test Name",
"url": "/test/url/",
"type": "f"
}
]
]
I want to ignore that "list" and parse a POJO in List of object ModelName. I am using Retrofit and Moshi Convertor but I am not sure how I can achieve this. Is there any way that I can intercept the response before it passed to Moshi Convertor or any different approach that I can go for.
Retrofit Snippet
private fun getRetrofit(): Retrofit {
return Retrofit.Builder()
.baseUrl(BuildConfig.API_URL)
.addConverterFactory(MoshiConverterFactory.create())
.client(getHTTPClient())
.build()
}
Retrofit offers custom converters (see official documentation),moshi also should offer something similar.
I do not have experience in using moshi, but I have checked documentation and source code - it looks it is possible.
Moshi offers custom adapters which should do things you need. Take a look on PolymorphicJsonAdapterFactory, it has methods fromJson() and toJson() which allows you manually parse json elements in which way you like.
Even more. PolymorphicJsonAdapterFactory looks as an option you need for this.
A JsonAdapter factory for objects that include type information in
the JSON. When decoding JSON. Moshi uses this type information to
determine which class to decode to. When encoding Moshi uses. the
object’s class to determine what type information to include.

Get particular key value from json in android (kotlin)

I'm beginner in android (Kotlin).I am getting the Following json from the HTTP Response.
{
"status": 1,
"userDetails": [
{
"AL_ID": "2",
"User_Id": "admin",
"User_Password": "admin",
"Created_Date": "2020-07-30 11:23:55"
}
],
"lastlogin": "2020-08-20 12:29:47"
}
I want to get status value from this json. How to get it.
You can use the built-in JSONObject and do something as shown below.
val json = JSONObject(jsonString) // String instance holding the above json
val status = json.getInt("status")
Having said that, I'd recommend you to take a look at Gson (for JSON serialization and deserialization) and Retrofit (an HTTP client for Android).
I would suggest using Gson library too, for android development in kotlin.
Also I would suggest to have the same DATA classes in kotlin as in database. In that way you can map objects fromJson and toJson with one line of code.
I found article that explains in details how to use Gson library with kotlin.
https://medium.com/#hissain.khan/parsing-with-google-gson-library-in-android-kotlin-7920e26f5520

Retrofit - Convert Json response to easily store data with Room

Is it possible to convert this :
{
"news": [
{
"nid": 1,
"type": "test1",
},
{
"nid": 2,
"type": "test2",
}
]
}
To this when I receive the result with Retrofit ?
{
"nid": 1,
"type": "test1",
},
{
"nid": 2,
"type": "test2",
}
Actually in my model, I have a NewsList object with a List of News inside (with value inside : nid, type).
And the Retrofit query looks like this :
#GET("test/test.json")
suspend fun getListNews(): Response<Newslist>
Everything is working fine, but now I need to save that data in a database with Room and it will be easier if the Retrofit query was like this :
#GET("test/test.json")
suspend fun getListNews(): Response<List<News>
What is the best way to achieve this ?
Convert Json response to get something like above ?
Keep things like this and Convert the NewsList to be able to be stored in the Room Database ?
The best way is to use RXJava or Coroutine of Kotlin.
In RXJava you can use map operator to transform your response object to list of objects.
Please refer below link to get some idea of using RXJava with retrofit and transforming results:
https://www.journaldev.com/20433/android-rxjava-retrofit
The best way is to have your backend server return the canonical json data.
If this is not possible, you can customize the converterFactor by addConverterFactory method,compatible with this data format in a custom converterFactor.
first, you must to have one layer for data provider to provide for consumer (activity, VM, fragment, etc).
in this layer, you have use case to define data collection from Cloud(Retrofit) or from Local Storage(Room). more info, i have sample here
Yes, you can, using data classes, you just need to create a data class called news with a list of items with "nid" and "type", in that cases I use a plugging of Android Studio Called Kotlin data class File from JSON
I think the better way is to return NewsList object, because it makes you easier to compatible with new feature update, like adding more fields to NewsList object. You can create a new layer for saving your data to room database, and convert the raw data to List for saving it.

Retrofit to parse json with an indefinite number of object names

I'm using retrofit to handle rest-api calls.
I have a rest API that returns the following json
"MyObject": {
"43508": {
"field1": 4339,
"field2": "val",
"field3": 15,
"field4": 586.78
},
"1010030": {
"field1": 1339,
"field2": "val212",
"field3": 1,
"field4": 86.78
},...
}
Please notice that the object MyObject contains objects with a name that is actually an id.
For all the other rest APIs I'm using retrofit without problems.
In this case it seems not possible to use the standard approach: defining a class containing the fields expected in the response.
Is there a way to transform this json into a json containing an array of
{
"field1": xxx,
"field2": "yyy",
"field3": www,
"field4": zzz
}
Or is there a better way to deal with this problem without going back to "manually" parsing the json?
Try to use next approach:
public class Response {
Map<String, YourObject> MyObject;
// getter, setter
}
public interface GitHubService {
#GET("some_path")
Call<Response> listMyObjects();
}
All you objects will be parsed to Map. You can get the list of all ids via keySet() method or list all entries with entrySet().
Try putting the annotation, SerializedName(nameOfField) over the variable name.
#SerializedName("13445345")
MyObject object;
Well my idea is quite manual, but it should work. I will not copy and paste another person's answer here, so take a look at this answer to see how to loop through all of the myObject's keys. Then for each of those keys, make a new JSONArray and add key value pair of fieldX-valueX.
This is just a basic idea, since I think you can handle the code yourself, you seem like a guy who knows his way around the simple stuff.

Deserializing array response with a wrapper

I'm attempting to use Retrofit for communicating with an API that returns JSON arrays with a wrapper object. That is, a request to /apples.json would return the following:
{
apples: [ {apple1}, {apple2}, ... ]
}
Retrofit appears to expect the response to be of the form:
[ {apple1}, {apple2}, ...]
Is there a simple configuration option to handle this without having to write a custom Gson deserializer?

Categories

Resources