Calling the map function on a Flowable of type Result throws a ClassCastException

Viewed 543

I am trying to map the values in a Flowable of type Result to a different Result type. In the map block, I am simply calling mapCatching on the Result. Instead of returning the mapped value, it throws a ClassCastException. I have written a simple test to illustrate the problem I'm having.

@Test
    fun test() {
        Flowable.just(Result.success(1))
                .map { result ->
                    result.mapCatching { input -> input.toString() }
                }
                .test()
                .values()
                .forEach {
                    println(it)
                }
    }

This returns the following exception:

java.lang.ClassCastException: kotlin.Result$Failure cannot be cast to kotlin.Result

Edit: Replacing the mapCatching method with my own mapping code causes the Flowable to terminate with a different ClassCastException:

@Test
    fun test() {
        Flowable.just(Result.success(1))
                .map { result ->
                    if (result.isFailure) {
                        return@map Result.failure<String>(result.exceptionOrNull()!!)
                    } else {
                        return@map Result.success(result.getOrNull()!!.toString())
                    }
                }
                .test()
                .errors()
                .forEach {
                    println(it)
                }
    }

This test prints the following:

java.lang.ClassCastException: kotlin.Result cannot be cast to java.lang.Number
1 Answers

The Result class is an inline class and the compiler internally tries to convert it to the wrapped type wherever possible. This works fine when calling from Kotlin code, but RxJava is written in Java. See this article for more information.

In this instance I managed to solve it by unwrapping the Result classes in the source and only using the wrapped types. The Errors were propagated and finally wrapped in a result class at the subscriber.

Something like this:

Flowable.just(1)
 .map { it.toString() }
 .map { Result.success(it) }
 .onErrorReturn { Result.failure(it) }
Related