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?
Related
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.
I have a generic method getData that should get from the server some POJOs of different objects. Before Retrofit 2.6 without coroutines I could create a method like this:
#POST("GetData")
fun getGenericData(#Query("sessionId") sessionId: UUID, #Body request: RemoteRequest): Call<ResponseBody>
An it was fine because I could handle the json contained in the body and deserialize it based on the object name declared in a property inside the json, but with Retrofit 2.6 and coroutines that is not possibile because the return type Call or ResponseBody throw an exception. I do not want to use Response because I do not know the type of the object at compile time and I want to deserialize the returned json separately. Any idea ?
How do I send the following object to server using retrofit 2:
{"list":[
{
"addrress1":
{"addressLine1":"EktaColony",
"addressLine2":"Warje",
"country":"India",
"state":"Maharashtra",
"city":"Pune",
"zipcode":411058},
},
{address2:{.....,.....,...}}
]}
I am using Rxjava.
You can send the json as body of HTTP request. Retrofit provides the annotation #Body for its use
So in your interface
#POST("/yourserver/api")
Observable<ResponseType> sendReq(#Body RequestParser parser);
Your RequestParser Object is the object mapped from the json string. You can use any Json serializer libraries like gson or jackson for it.
I'm having an issue with an API that could return either ARRAY or OBJECT, below are the data format:
OBJECT format:
{
"info":"no package",
"time":"04-20-2016"
}
ARRAY format:
[
{
"package_id":"1234",
"from":"CA",
"arrive_time":"05-02-2016"
},
{
"package_id":"4567",
"from":"DE",
"arrive_time":"05-04-2016"
}
]
After checked some posts (Custom converter for Retrofit 2, Multiple converters with Retrofit 2), I have some clue the it should be dealed with Gson deserializer or Custom converter, but my case seems a little different. Then how to deal with it? Thanks in advance.
Update: change the example to a more proper one.
Chaosphinx
I agree your problem is different from this posts that you have referenced.
Your first Json has informations about and exception in your request and the second one is returned when your request was successful. I can suggest you to check the Response HTTP Code before to convert the Json. If the code is 202 (java.net.HttpURLConnection.HTTP_OK), is because you request was successful and the API will return the second Json, that you will convert to object. If the code is something else is because an exception has happened and you should deal with it in a different way.
An example:
Response<List<MyObject>> response = myResource.myMethod().execute();
switch (response.code()) {
case HTTP_OK:
return response.body();
default:
//OPS! Request has failed!
}
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
}
]
}