Related
Im migrating from using Volley to Retrofit, I already have gson class that I used before for converting JSONObject reponse to a object that implements gson annotations. When I'm trying to make http get request using retrofit but then my app crashes with this error :
Unable to start activity ComponentInfo{com.lightbulb.pawesome/com.example.sample.retrofit.SampleActivity}: java.lang.IllegalArgumentException: Unable to create converter for class com.lightbulb.pawesome.model.Pet
for method GitHubService.getResponse
Im following the guide in retrofit site and I come up with these implementations :
This is my activity where I am trying to execute the retro http request:
public class SampleActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sample);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("**sample base url here**")
.build();
GitHubService service = retrofit.create(GitHubService.class);
Call<Pet> callPet = service.getResponse("41", "40");
callPet.enqueue(new Callback<Pet>() {
#Override
public void onResponse(Response<Pet> response) {
Log.i("Response", response.toString());
}
#Override
public void onFailure(Throwable t) {
Log.i("Failure", t.toString());
}
});
try{
callPet.execute();
} catch (IOException e){
e.printStackTrace();
}
}
}
My interface which turned to be my API
public interface GitHubService {
#GET("/ **sample here** /{petId}/{otherPet}")
Call<Pet> getResponse(#Path("petId") String userId, #Path("otherPet") String otherPet);
}
And finally the Pet class which should be the reponse:
public class Pet implements Parcelable {
public static final String ACTIVE = "1";
public static final String NOT_ACTIVE = "0";
#SerializedName("is_active")
#Expose
private String isActive;
#SerializedName("pet_id")
#Expose
private String petId;
#Expose
private String name;
#Expose
private String gender;
#Expose
private String age;
#Expose
private String breed;
#SerializedName("profile_picture")
#Expose
private String profilePicture;
#SerializedName("confirmation_status")
#Expose
private String confirmationStatus;
/**
*
* #return
* The confirmationStatus
*/
public String getConfirmationStatus() {
return confirmationStatus;
}
/**
*
* #param confirmationStatus
* The confirmation_status
*/
public void setConfirmationStatus(String confirmationStatus) {
this.confirmationStatus = confirmationStatus;
}
/**
*
* #return
* The isActive
*/
public String getIsActive() {
return isActive;
}
/**
*
* #param isActive
* The is_active
*/
public void setIsActive(String isActive) {
this.isActive = isActive;
}
/**
*
* #return
* The petId
*/
public String getPetId() {
return petId;
}
/**
*
* #param petId
* The pet_id
*/
public void setPetId(String petId) {
this.petId = petId;
}
/**
*
* #return
* The name
*/
public String getName() {
return name;
}
/**
*
* #param name
* The name
*/
public void setName(String name) {
this.name = name;
}
/**
*
* #return
* The gender
*/
public String getGender() {
return gender;
}
/**
*
* #param gender
* The gender
*/
public void setGender(String gender) {
this.gender = gender;
}
/**
*
* #return
* The age
*/
public String getAge() {
return age;
}
/**
*
* #param age
* The age
*/
public void setAge(String age) {
this.age = age;
}
/**
*
* #return
* The breed
*/
public String getBreed() {
return breed;
}
/**
*
* #param breed
* The breed
*/
public void setBreed(String breed) {
this.breed = breed;
}
/**
*
* #return
* The profilePicture
*/
public String getProfilePicture() {
return profilePicture;
}
/**
*
* #param profilePicture
* The profile_picture
*/
public void setProfilePicture(String profilePicture) {
this.profilePicture = profilePicture;
}
protected Pet(Parcel in) {
isActive = in.readString();
petId = in.readString();
name = in.readString();
gender = in.readString();
age = in.readString();
breed = in.readString();
profilePicture = in.readString();
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(isActive);
dest.writeString(petId);
dest.writeString(name);
dest.writeString(gender);
dest.writeString(age);
dest.writeString(breed);
dest.writeString(profilePicture);
}
#SuppressWarnings("unused")
public static final Parcelable.Creator<Pet> CREATOR = new Parcelable.Creator<Pet>() {
#Override
public Pet createFromParcel(Parcel in) {
return new Pet(in);
}
#Override
public Pet[] newArray(int size) {
return new Pet[size];
}
};
}
If anyone ever comes across this in the future because you are trying to define your own custom converter factory and are getting this error, it can also be caused by having multiple variables in a class with a misspelled or the same serialized name. IE:
public class foo {
#SerializedName("name")
String firstName;
#SerializedName("name")
String lastName;
}
Having serialized names defined twice (likely by mistake) will also throw this exact same error.
Update: Keep in mind that this logic also holds true via inheritance. If you extend to a parent class with an object that has the same Serialized name as you do in the sub-class, it will cause this same problem.
Prior to 2.0.0, the default converter was a gson converter, but in 2.0.0 and later the default converter is ResponseBody. From the docs:
By default, Retrofit can only deserialize HTTP bodies into OkHttp's
ResponseBody type and it can only accept its RequestBody type for
#Body.
In 2.0.0+, you need to explicitly specify you want a Gson converter:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("**sample base url here**")
.addConverterFactory(GsonConverterFactory.create())
.build();
You will also need to add the following dependency to your gradle file:
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
Use the same version for the converter as you do for your retrofit. The above matches this retrofit dependency:
compile ('com.squareup.retrofit2:retrofit:2.1.0')
Also, note as of writing this, the retrofit docs are not completely updated, which is why that example got you into trouble. From the docs:
Note: This site is still in the process of being expanded for the new 2.0 APIs.
just make sure that you are not using the same serialize name twice
#SerializedName("name") val name: String
#SerializedName("name") val firstName: String
just remove one of them
Based on top comment I updated my imports
implementation 'com.squareup.retrofit2:retrofit:2.1.0'
implementation 'com.squareup.retrofit2:converter-gson:2.1.0'
I've used http://www.jsonschema2pojo.org/ in order to create pojo's from Spotify json results and making sure to specify Gson format.
These days there are Android Studio plugins which can create the pojo's or Kotlin data models for you. One great option for mac is Quicktype.
https://itunes.apple.com/us/app/paste-json-as-code-quicktype/id1330801220
In my case, I had a TextView object inside my modal class and GSON did not know how to serialize it. Marking it as 'transient' solved the issue.
#Silmarilos's post helped me solve this. In my case, it was that I used "id" as a serialized name, like this:
#SerializedName("id")
var node_id: String? = null
and I changed it to
#SerializedName("node_id")
var node_id: String? = null
All working now. I forgot that 'id' is a default attribute.
In my case, it was due to trying to take a List being returned by my service into an ArrayList. So what I had was:
#Json(name = "items")
private ArrayList<ItemModel> items;
when I should've had
#Json(name = "items")
private List<ItemModel> items;
Hope this helps someone!
In build.gradle changing
minifyEnabled true
to
minifyEnabled false
has solved my problem.
In my case I was using the Moshi library with Retrofit 2.0, i.e
// Moshi
implementation 'com.squareup.moshi:moshi-kotlin:1.9.3'
// Retrofit with Moshi Converter
implementation 'com.squareup.retrofit2:converter-moshi:2.9.0'
I forgot to pass in the custom Moshi json converter adapter factory object to the moshi converter factory constructor.
private val moshi = Moshi.Builder() // adapter
.add(KotlinJsonAdapterFactory())
.build()
private val retrofit = Retrofit.Builder()
.addConverterFactory(MoshiConverterFactory.create()) // <- missing moshi json adapter insance
.baseUrl(BASE_URL)
.build()
Fix: .addConverterFactory(MoshiConverterFactory.create(moshi))
This may help someone
In my case mistakenly I wrote SerializedName like this
#SerializedName("name","time")
String name,time;
It should be
#SerializedName("name")
String name;
#SerializedName("time")
String time;
In my case, the problem was that my SUPERCLASS model had this field defined in it. Very stupid, I know....
Hey i was going through the same issue today took me a whole day to find a solution but this is the solution i found finally.
Am using Dagger in my code and i needed to implement the Gson converter in my retrofit instance.
so this was my code before
#Provides
#Singleton
Retrofit providesRetrofit(Application application,OkHttpClient client) {
String SERVER_URL=URL;
Retrofit.Builder builder = new Retrofit.Builder();
builder.baseUrl(SERVER_URL);
return builder
.client(client)
.build();
}
this was what i ended up with
#Provides
#Singleton
Retrofit providesRetrofit(Application application,OkHttpClient client, Gson gson) {
String SERVER_URL=URL;
Retrofit.Builder builder = new Retrofit.Builder();
builder.baseUrl(SERVER_URL);
return builder
.client(client)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
}
notice how there is no converter in the first example and the addition if you haven't instantiated Gson you add it like this
#Provides
#Singleton
Gson provideGson() {
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES);
return gsonBuilder.create();
}
and ensure you have included it in the method call for retrofit.
once again hope this helps some one like me.
In my case using kotlinx.serialization, the same exception was raised by retrofit,
it was due to the missing #Serializable annotation.
#Serializable
data class MyClass(
val id: String
)
In my case I was missing the Serialization attribute.
I had to add #kotlinx.serialization.Serializable before every data class:
#kotlinx.serialization.Serializable
data class RadioSearchPodcastDto(
val playables: List<Playable>,
val searchTag: SearchTag,
val totalCount: Int
)
Retrofit interface:
interface PodcastRadioApi {
#GET("/podcasts/search")
suspend fun getPodcastBySearch(#Query("query") query: String,
#Query("count") count: Int,
#Query("offset") offset: Int,
#Query("partner") partner: String): RadioSearchPodcastDto
}
With every, I mean the main class and all sub-classes (Playable, SearchTag, ...)
In my cas i had to change ConverterFactory from moshi to Gson
and it woked will.
.addConverterFactory(GsonConverterFactory.create())
in my case, I am using Moshi with Retrofit and my mistake was :
I did not define a body for object that include in Response class service.
for example:
#JsonSerializable
data class Balance(
#field:Json(name = "balance") var balance: Double,
#field:Json(name = "currency") var currency: Currency
and the Currency class was emty. so I complete it and the problem fixed!
I have retrieve data from Server using Retrofit and now I am trying to store with sqlite database
WebserviceHandler.getImagePathSelectAl()
.subscribeOn(Schedulers.io())
.flatMap(s -> WebserviceHandler.getCtbLeidSource())
.subscribeOn(Schedulers.io())
.subscribe(.................);
and response model class like
public class ImagePathResponse {
#SerializedName("Message")
#Expose
private String message;
#SerializedName("HasColumns")
#Expose
private Integer hasColumns;
#SerializedName("ErrorMessage")
#Expose
private String errorMessage;
#SerializedName("ImagePath_insert")
#Expose
private List<ImagePath> imagePathInsert = null;
#SerializedName("ImagePath_update")
#Expose
private List<ImagePath> imagePathUpdate = null;
and
public class LeedSourceResponse {
#SerializedName("Message")
#Expose
private String message;
#SerializedName("HasColumns")
#Expose
private Integer hasColumns;
#SerializedName("ErrorMessage")
#Expose
private String errorMessage;
#SerializedName("LeedSource_insert")
#Expose
private List<LeedSource> leedSourceInsert = null;
#SerializedName("LeedSource_update")
#Expose
private List<LeedSource> leedSourceUpdate = null;
now i want to insert and update sqlite db in each response, how can achieve this. I am new to RxJava and RxAndroid
You can check Rooms persistence library its a sql library for androidRooms , but in this case I would recommend you using RealmDb instead of sql, its much faster and would work perfectly if you want to save your date for every response.
I am using Retrofit2 to send and receive requests to my server.
Here are my API interface and Model class.
Interface
public interface ApiInterface {
#POST("/users/")
Call<User> signUp(#Body User user);
#POST("/login_url/")
Call<User> login(#Body User user);
}
Retrofit client
public class RetrofitClient {
private static Retrofit retrofit = null;
public static Retrofit getRestClient(String baseUrl) {
if (retrofit == null) {
retrofit = new Retrofit.Builder().baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
POJO class
public class User {
#SerializedName("id")
private Integer id;
#SerializedName("email")
#Expose
private String email;
#SerializedName("first_name")
private String firstName;
#SerializedName("last_name")
private String lastName;
#SerializedName("password")
#Expose
private String password;
}
I have exposed email and password so that in login request these 2 parameters will be added.
But for another request like Sign up, I required a first name and last name also to be sent along with email and password.
Can I use same "User" class for both ? because if I expose the first name and last name then, those fields will be also sent in login request.
Is there any other way or should I make different POJO classes for both request ?
Instead of sending the whole class , you can use #Field annotation , so your login callback will be something like this :
#FormUrlEncoded
#POST("/login_url/")
Call<User> login(#field("email")String email,#field("password")String password);
#FormUrlEncoded denotes that the request body will use form URL encoding. Fields should be declared as parameters and annotated with #Field.
Can I use same "User" class for both ?
Yes , you can use the same Model as #Body for both requests !
Just make sure where you don't need the required variables just omit them !!
Remove the #SerializedName and #Expose , these are not required and give the variable names according to the json KEYs
public class User {
private Integer id;
private String email;
private String firstName;
private String lastName;
private String password;
}
Edit
Suppose for example , for one request you need :-
4 params you set the model user as
new User(id,email,firstname,lastname); // dont init the password attribute
5 params you set all values to the model like
new User(id,email,firstname,lastname,password);
Im migrating from using Volley to Retrofit, I already have gson class that I used before for converting JSONObject reponse to a object that implements gson annotations. When I'm trying to make http get request using retrofit but then my app crashes with this error :
Unable to start activity ComponentInfo{com.lightbulb.pawesome/com.example.sample.retrofit.SampleActivity}: java.lang.IllegalArgumentException: Unable to create converter for class com.lightbulb.pawesome.model.Pet
for method GitHubService.getResponse
Im following the guide in retrofit site and I come up with these implementations :
This is my activity where I am trying to execute the retro http request:
public class SampleActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sample);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("**sample base url here**")
.build();
GitHubService service = retrofit.create(GitHubService.class);
Call<Pet> callPet = service.getResponse("41", "40");
callPet.enqueue(new Callback<Pet>() {
#Override
public void onResponse(Response<Pet> response) {
Log.i("Response", response.toString());
}
#Override
public void onFailure(Throwable t) {
Log.i("Failure", t.toString());
}
});
try{
callPet.execute();
} catch (IOException e){
e.printStackTrace();
}
}
}
My interface which turned to be my API
public interface GitHubService {
#GET("/ **sample here** /{petId}/{otherPet}")
Call<Pet> getResponse(#Path("petId") String userId, #Path("otherPet") String otherPet);
}
And finally the Pet class which should be the reponse:
public class Pet implements Parcelable {
public static final String ACTIVE = "1";
public static final String NOT_ACTIVE = "0";
#SerializedName("is_active")
#Expose
private String isActive;
#SerializedName("pet_id")
#Expose
private String petId;
#Expose
private String name;
#Expose
private String gender;
#Expose
private String age;
#Expose
private String breed;
#SerializedName("profile_picture")
#Expose
private String profilePicture;
#SerializedName("confirmation_status")
#Expose
private String confirmationStatus;
/**
*
* #return
* The confirmationStatus
*/
public String getConfirmationStatus() {
return confirmationStatus;
}
/**
*
* #param confirmationStatus
* The confirmation_status
*/
public void setConfirmationStatus(String confirmationStatus) {
this.confirmationStatus = confirmationStatus;
}
/**
*
* #return
* The isActive
*/
public String getIsActive() {
return isActive;
}
/**
*
* #param isActive
* The is_active
*/
public void setIsActive(String isActive) {
this.isActive = isActive;
}
/**
*
* #return
* The petId
*/
public String getPetId() {
return petId;
}
/**
*
* #param petId
* The pet_id
*/
public void setPetId(String petId) {
this.petId = petId;
}
/**
*
* #return
* The name
*/
public String getName() {
return name;
}
/**
*
* #param name
* The name
*/
public void setName(String name) {
this.name = name;
}
/**
*
* #return
* The gender
*/
public String getGender() {
return gender;
}
/**
*
* #param gender
* The gender
*/
public void setGender(String gender) {
this.gender = gender;
}
/**
*
* #return
* The age
*/
public String getAge() {
return age;
}
/**
*
* #param age
* The age
*/
public void setAge(String age) {
this.age = age;
}
/**
*
* #return
* The breed
*/
public String getBreed() {
return breed;
}
/**
*
* #param breed
* The breed
*/
public void setBreed(String breed) {
this.breed = breed;
}
/**
*
* #return
* The profilePicture
*/
public String getProfilePicture() {
return profilePicture;
}
/**
*
* #param profilePicture
* The profile_picture
*/
public void setProfilePicture(String profilePicture) {
this.profilePicture = profilePicture;
}
protected Pet(Parcel in) {
isActive = in.readString();
petId = in.readString();
name = in.readString();
gender = in.readString();
age = in.readString();
breed = in.readString();
profilePicture = in.readString();
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(isActive);
dest.writeString(petId);
dest.writeString(name);
dest.writeString(gender);
dest.writeString(age);
dest.writeString(breed);
dest.writeString(profilePicture);
}
#SuppressWarnings("unused")
public static final Parcelable.Creator<Pet> CREATOR = new Parcelable.Creator<Pet>() {
#Override
public Pet createFromParcel(Parcel in) {
return new Pet(in);
}
#Override
public Pet[] newArray(int size) {
return new Pet[size];
}
};
}
If anyone ever comes across this in the future because you are trying to define your own custom converter factory and are getting this error, it can also be caused by having multiple variables in a class with a misspelled or the same serialized name. IE:
public class foo {
#SerializedName("name")
String firstName;
#SerializedName("name")
String lastName;
}
Having serialized names defined twice (likely by mistake) will also throw this exact same error.
Update: Keep in mind that this logic also holds true via inheritance. If you extend to a parent class with an object that has the same Serialized name as you do in the sub-class, it will cause this same problem.
Prior to 2.0.0, the default converter was a gson converter, but in 2.0.0 and later the default converter is ResponseBody. From the docs:
By default, Retrofit can only deserialize HTTP bodies into OkHttp's
ResponseBody type and it can only accept its RequestBody type for
#Body.
In 2.0.0+, you need to explicitly specify you want a Gson converter:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("**sample base url here**")
.addConverterFactory(GsonConverterFactory.create())
.build();
You will also need to add the following dependency to your gradle file:
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
Use the same version for the converter as you do for your retrofit. The above matches this retrofit dependency:
compile ('com.squareup.retrofit2:retrofit:2.1.0')
Also, note as of writing this, the retrofit docs are not completely updated, which is why that example got you into trouble. From the docs:
Note: This site is still in the process of being expanded for the new 2.0 APIs.
just make sure that you are not using the same serialize name twice
#SerializedName("name") val name: String
#SerializedName("name") val firstName: String
just remove one of them
Based on top comment I updated my imports
implementation 'com.squareup.retrofit2:retrofit:2.1.0'
implementation 'com.squareup.retrofit2:converter-gson:2.1.0'
I've used http://www.jsonschema2pojo.org/ in order to create pojo's from Spotify json results and making sure to specify Gson format.
These days there are Android Studio plugins which can create the pojo's or Kotlin data models for you. One great option for mac is Quicktype.
https://itunes.apple.com/us/app/paste-json-as-code-quicktype/id1330801220
In my case, I had a TextView object inside my modal class and GSON did not know how to serialize it. Marking it as 'transient' solved the issue.
#Silmarilos's post helped me solve this. In my case, it was that I used "id" as a serialized name, like this:
#SerializedName("id")
var node_id: String? = null
and I changed it to
#SerializedName("node_id")
var node_id: String? = null
All working now. I forgot that 'id' is a default attribute.
In my case, it was due to trying to take a List being returned by my service into an ArrayList. So what I had was:
#Json(name = "items")
private ArrayList<ItemModel> items;
when I should've had
#Json(name = "items")
private List<ItemModel> items;
Hope this helps someone!
In my case I was using the Moshi library with Retrofit 2.0, i.e
// Moshi
implementation 'com.squareup.moshi:moshi-kotlin:1.9.3'
// Retrofit with Moshi Converter
implementation 'com.squareup.retrofit2:converter-moshi:2.9.0'
I forgot to pass in the custom Moshi json converter adapter factory object to the moshi converter factory constructor.
private val moshi = Moshi.Builder() // adapter
.add(KotlinJsonAdapterFactory())
.build()
private val retrofit = Retrofit.Builder()
.addConverterFactory(MoshiConverterFactory.create()) // <- missing moshi json adapter insance
.baseUrl(BASE_URL)
.build()
Fix: .addConverterFactory(MoshiConverterFactory.create(moshi))
This may help someone
In my case mistakenly I wrote SerializedName like this
#SerializedName("name","time")
String name,time;
It should be
#SerializedName("name")
String name;
#SerializedName("time")
String time;
In my case, the problem was that my SUPERCLASS model had this field defined in it. Very stupid, I know....
In build.gradle changing
minifyEnabled true
to
minifyEnabled false
has solved my problem.
Hey i was going through the same issue today took me a whole day to find a solution but this is the solution i found finally.
Am using Dagger in my code and i needed to implement the Gson converter in my retrofit instance.
so this was my code before
#Provides
#Singleton
Retrofit providesRetrofit(Application application,OkHttpClient client) {
String SERVER_URL=URL;
Retrofit.Builder builder = new Retrofit.Builder();
builder.baseUrl(SERVER_URL);
return builder
.client(client)
.build();
}
this was what i ended up with
#Provides
#Singleton
Retrofit providesRetrofit(Application application,OkHttpClient client, Gson gson) {
String SERVER_URL=URL;
Retrofit.Builder builder = new Retrofit.Builder();
builder.baseUrl(SERVER_URL);
return builder
.client(client)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
}
notice how there is no converter in the first example and the addition if you haven't instantiated Gson you add it like this
#Provides
#Singleton
Gson provideGson() {
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES);
return gsonBuilder.create();
}
and ensure you have included it in the method call for retrofit.
once again hope this helps some one like me.
In my case using kotlinx.serialization, the same exception was raised by retrofit,
it was due to the missing #Serializable annotation.
#Serializable
data class MyClass(
val id: String
)
In my case I was missing the Serialization attribute.
I had to add #kotlinx.serialization.Serializable before every data class:
#kotlinx.serialization.Serializable
data class RadioSearchPodcastDto(
val playables: List<Playable>,
val searchTag: SearchTag,
val totalCount: Int
)
Retrofit interface:
interface PodcastRadioApi {
#GET("/podcasts/search")
suspend fun getPodcastBySearch(#Query("query") query: String,
#Query("count") count: Int,
#Query("offset") offset: Int,
#Query("partner") partner: String): RadioSearchPodcastDto
}
With every, I mean the main class and all sub-classes (Playable, SearchTag, ...)
In my cas i had to change ConverterFactory from moshi to Gson
and it woked will.
.addConverterFactory(GsonConverterFactory.create())
in my case, I am using Moshi with Retrofit and my mistake was :
I did not define a body for object that include in Response class service.
for example:
#JsonSerializable
data class Balance(
#field:Json(name = "balance") var balance: Double,
#field:Json(name = "currency") var currency: Currency
and the Currency class was emty. so I complete it and the problem fixed!
I'm working on API Requests with Retrofit(1.9.0) and gson library (1.7.0 I have compatibility issues with version 2.3.1 of gson) on Android, I make some request to an API which have same format of response but different content following the url call, but I encounter a problem for a deserialization of one answer which there is array inside. This is an example of the json I want to deserialize :
{
"http_code":200,
"content":[
{
"name":"Groult Christian",
"location":[
48.897655,
2.252462
],
"website":null,
"address":{
"street_address":"XXXXXX",
"city":"XXXXXX",
"state":null,
"postal_code":"XXXXXX",
"country":"XXXXXX"
},
"global_score":0,
"popularity_score":0,
"quality_score":0,
"createdAt":"2015-02-18T02:13:05.068Z",
"updatedAt":"2015-02-18T02:13:05.068Z",
"id":"54e3f531775288ca572872ac"
},
...
]
}
My DeserializerJson and how I call it for retrofit:
public class DeserializerJson<T> implements JsonDeserializer<T> {
#Override
public T deserialize(JsonElement je, Type type, JsonDeserializationContext jdc)
throws JsonParseException
{
// Get the "content" element from the parsed JSON
JsonElement content = je.getAsJsonObject().get("content");
// Deserialize it. You use a new instance of Gson to avoid infinite recursion
// to this deserializer
return new Gson().fromJson(content, type);
}
}
...
Gson gson = new GsonBuilder()
.registerTypeAdapter(ContentUser.class, new DeserializerJson<ContentUser>())
.registerTypeAdapter(DeviceInfo.class, new DeserializerJson<DeviceInfo>())
.registerTypeAdapter(PlacesModel.class, new DeserializerJson<PlacesModel>())
.create();
RestAdapter restAdapter = new RestAdapter.Builder()
.setLogLevel(RestAdapter.LogLevel.BASIC)
.setConverter(new GsonConverter(gson))
...
...
and my different models:
public class PlacesModel {
#SerializedName("name")
#Expose
private String name;
#SerializedName("location")
#Expose
private List<Double> location = new ArrayList<Double>();
#SerializedName("website")
#Expose
private Object website;
#SerializedName("address")
#Expose
private AddressModel address;
#SerializedName("global_score")
#Expose
private Integer globalScore;
#SerializedName("popularity_score")
#Expose
private Integer popularityScore;
#SerializedName("quality_score")
#Expose
private Integer qualityScore;
#SerializedName("createdAt")
#Expose
private String createdAt;
#SerializedName("updatedAt")
#Expose
private String updatedAt;
#Expose
#SerializedName("id")
private String id;
/* Getters and Setters... */
}
public class AddressModel {
#SerializedName("street_address")
#Expose
private String streetAddress;
#SerializedName("city")
#Expose
private String city;
#SerializedName("state")
#Expose
private Object state;
#SerializedName("postal_code")
private String postalCode;
#SerializedName("country")
#Expose
private String country;
/* Getters and Setters... */
}
url call in Api Manager is like this:
#GET("/places")
public void getPlaces(RestCallback<List<PlacesModel>> callback);
But when I do the call I get this error : com.google.gson.JsonParseException: The JsonDeserializer com.google.gson.DefaultTypeAdapters$CollectionTypeAdapter#3b8aa06 failed to deserialize json object
Everything is fine for other call I get all content and so with no problem but one where there is array inside content I got an error and I don't understand why I believed if I just put a list of my model it will be fine but it doesn't work.
I think I miss something so if someone can help me
Thanks in advance
The problem of your issue is that you register DeserializerJson for PlacesModel class and in getPlaces method your response is List<PlacesModel> class. List<PlacesModel> is a different class as PlacesModelso Gson doesn't know how to deserialise List<PlacesModel>. What you have to do is register one more Deserialiser by this method:
.registerTypeAdapter(List.class, new DeserializerJson<List<PlacesModel>>())
If you use more than one type of List (I mean List<PlacesModel> and List< DeviceInfo >) You can define your own TypeAdapter or you cN change list to array and register deserialiser for them as is shown below
.registerTypeAdapter(PlacesModel[].class, new DeserializerJson<PlacesModel[]>())
Now everything works fine for yours json.