Reputation: 811
I got some strange behaviour when using Retrofit+Gson+RxJava
Here is my retrifit object
Retrofit.Builder()
.baseUrl(Constants.Urls.URL_BASE)
.addConverterFactory(GsonConverterFactory.create(Gson()))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(client)
.build()
here is my data class
data class User(
val id:Int,
val email:String,
val name:String)
here is my retrofit interface
@Multipart
@POST(Constants.Urls.URL_LOGIN)
fun makeLogin(@PartMap map: Map<String, String?>): Observable<Model_User>
When login is successful all works as it should, but i get strange behavoiur when instead of json object in reponse i got string error e.g.
{
"error": {
"code": 400,
"message": "Wrong password"
}
}
Observable calls a success in subscription, with User object. And this object has null values on fields that cant be null.
my_api.makeLogin(map)
.subscribe(
{
//Here i got User(id = null,email = null,name = null)
},
{
//But i need to call error here on parsing failed
})
What should i do to throw error before onNext called? Is it possible to make retrofit throw error when Gson parsing fails instead of emmiting empty Object?
Upvotes: 0
Views: 263
Reputation: 743
Firstly, this is a bit strange that when a login error occurrs, the resposnse from your server does not trigger the observable's error. Probably there are some backend issues?
Secondly, unfortunately Gson is not null-safe, as it uses reflection for parsing the objects, so even not nullable field can have null
value if none is provided (see eg. this article). They even have a feature request to provide a mechanism for forcing an exception then requested field is not in the json (stuck there for 5 years).
For now, probably the best option to handle this is to create two different models: an API model with all fields nullable, and domain model (the User
model that you already have) and flatMap the the mapping result. Eg:
my_api.makeLogin(map)
.flatMap { apiUser ->
try {
val user = apiUser.mapToDomain() //throw exception while mapping if field is missing
Single.just(user)
}catch(e: Exception){
Single.error<User>(IllegalStateException())
}
}
.subscribe( ... )
Upvotes: 1