Ошибка при модификации + Gson + Rx Java при разборе - PullRequest
0 голосов
/ 20 апреля 2020

У меня странное поведение при использовании Retrofit + Gson + Rx Java

Вот мой объект для переобработки

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

Вот мой класс данных

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

Наблюдаемые вызовы успешны в подписке с объектом 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 вместо пустого объекта?

1 Ответ

1 голос
/ 21 апреля 2020

Во-первых, немного странно, что при возникновении ошибки входа в систему ответ вашего сервера не вызывает ошибку наблюдаемого. Возможно, есть какие-то проблемы с бэкендом?

Во-вторых, к сожалению, Gson не является нуль-безопасным, так как он использует отражение для разбора объектов, поэтому даже не обнуляемое поле может иметь значение null, если ничего не указано (см., Например, . эта статья ). У них даже есть запрос функции , чтобы обеспечить механизм для принудительного исключения, тогда запрошенное поле отсутствует в 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( ... )
...