Retrofit+Gson+RxJava 解析失败抛出错误

Retrofit+Gson+RxJava throw error on parsing failed

我在使用 Retrofit+Gson+RxJava 时遇到了一些奇怪的行为

这是我的改造对象

Retrofit.Builder()
            .baseUrl(Constants.Urls.URL_BASE)
            .addConverterFactory(GsonConverterFactory.create(Gson()))
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .client(client)
            .build()

这是我的数据class

data class User(
        val id:Int,
        val email:String,
        val name:String)

这是我改造后的界面

    @Multipart
    @POST(Constants.Urls.URL_LOGIN)
    fun makeLogin(@PartMap map: Map<String, String?>): Observable<Model_User>

当登录成功时,一切正常,但是当我得到字符串错误而不是 json 对象作为响应时,我得到了奇怪的行为,例如

{
    "error": {
        "code": 400,
        "message": "Wrong password"
    }
}

Observable 使用 User 对象调用订阅成功。并且此对象在不能为空的字段上具有空值。

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
                })

在 onNext 调用之前我应该​​怎么做才能抛出错误?当 Gson 解析失败而不是发出空对象时,是否可以进行改造抛出错误?

首先,这有点奇怪,当发生登录错误时,来自您的服务器的响应不会触发可观察对象的错误。可能有一些后端问题?

其次,不幸的是 Gson 不是空安全的,因为它使用反射来解析对象,所以如果提供了 none,即使不可空字段也可以具有 null 值(参见例如 this article). They even have a feature request 提供一种强制异常的机制,然后请求的字段不在 json 中(在那里停留了 5 年)。

目前,处理这个问题的最佳选择可能是创建两个不同的模型:一个所有字段都可以为空的 API 模型和域模型(您已经拥有的 User 模型) flatMap 是映射结果。例如:

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( ... )