捕获错误并在RxJava2中返回一个新类型

时间:2018-06-16 23:54:32

标签: java kotlin rx-java rx-java2 reactivex

我有一个流:

val symbols: Single<List<Symbol>>

现在我想使用map()将流转换为UI状态:

private fun cool(): Single<SymbolContract.State> =
    symbols.map { SymbolContract.State.Symbols(it) }

我想要做的是捕获上游symbols单个错误,以便我可以捕获任何错误然后返回SymbolContract.State.GeneralError()

我想要像onErrorMap()之类的东西。不幸的是,将onErrorResumeItem放在symbols上不起作用,因为它需要返回List<Symbol>

我可以想到一些丑陋的方法来做到这一点,但最干净的是什么?

2 个答案:

答案 0 :(得分:1)

我建议你使用全局处理错误。我给你一个样本,这样你就可以得到这个想法。 (它是kotlin)你可以捕获你想要的异常,其中一些是我的自定义异常。请记住,这个示例是关于Reactive Webflux但你明白了。它会与其他人相似

@Configuration
class ExceptionTranslator {

    @Bean
    @Order(-1)
    fun handle(objectMapper: ObjectMapper): ErrorWebExceptionHandler {
        return ErrorWebExceptionHandler { exchange, ex ->
            if (exchange.response.isCommitted) {
                return@ErrorWebExceptionHandler Mono.error(ex)
            }

            val response = exchange.response
            response.statusCode = HttpStatus.INTERNAL_SERVER_ERROR
            response.headers.contentType = MediaType.APPLICATION_PROBLEM_JSON_UTF8

            val url: String

            var message = ex.message
            var params = mutableMapOf<String, Any>()

            when (ex) {
                is ParametricException -> {
                    url = ex.url
                    params = ex.params
                }
                is BaseException -> {
                    url = ex.url
                }
                is BadCredentialsException -> {
                    url = INVALID_CREDENTIAL_TYPE
                    message = ex.message ?: "Wrong Credentials"
                }
                is ConcurrencyFailureException -> {
                    url = INTERNAL_TYPE
                    message = ERR_CONCURRENCY_FAILURE
                }
                is MethodArgumentNotValidException -> {
                    val result = ex.bindingResult
                    val fieldErrors = result.fieldErrors.map {
                        FieldErrorVM(it.objectName, it.field, it.code ?: "Unknown")
                    }

                    url = CONSTRAINT_VIOLATION_TYPE
                    message = ERR_VALIDATION
                    params = Collections.singletonMap("errors", fieldErrors)
                }
                else -> url = INTERNAL_TYPE
            }

            if (ex is BaseException) {
                response.statusCode = HttpStatus.valueOf(ex.status.code())
            }

            val bytes = objectMapper.writeValueAsBytes(ProblemVM(url, message ?: "Internal Error", params))
            val buffer = response.bufferFactory().wrap(bytes)
            response.writeWith(Mono.just(buffer))
        }
    }

}

答案 1 :(得分:0)

找到一个干净的答案:

all3again :: Int -> Int
all3again val =
    ite cond1 f1 val
    |> ite cond2 f2
    |> ite cond3 f3

ite :: (a -> Bool) -> (a -> a) -> a -> a
ite c a v | c v = a v
          | otherwise = v

(|>) :: a -> (a -> b) -> b
(|>) v f = f v
infixl 5 |>

onErrorReturnItem必须在地图之后,地图需要显式的类型参数。