RxJavaでカスタムオペレータを作るときの自分用テンプレ。
少しだけ解説すると、noOpは何も加工しません。
myMapは、Observable#map(Function<? super T,? extends R> mapper)と機能は変わりません。
errMapは、流れてきたエラー捕まえて加工したあと、再度エラーを流します。
カスタムオペレータを書く動機になったのは、そのオペレータのうちerrMapです。
流れてきたExceptionを加工したくなったときに、Observableでは提供されていないようなので自作しました。
class LiftTest {
fun <T> Observable<T>.noOp(): Observable<T> {
return lift { observer ->
object : Observer<T> {
override fun onComplete() { return observer.onComplete() }
override fun onSubscribe(d: Disposable) { return observer.onSubscribe(d) }
override fun onNext(t: T) { return observer.onNext(t) }
override fun onError(e: Throwable) { return observer.onError(e) }
}
}
}
fun <U, D> Observable<U>.myMap(func: (U) -> D): Observable<D> {
return lift { observer ->
object : Observer<U> {
override fun onComplete() { return observer.onComplete() }
override fun onSubscribe(d: Disposable) { return observer.onSubscribe(d) }
override fun onNext(t: U) { return observer.onNext(func(t)) }
override fun onError(e: Throwable) { return observer.onError(e) }
}
}
}
fun <T> Observable<T>.errMap(func : (Throwable) -> Throwable): Observable<T> {
return lift { observer ->
object : Observer<T> {
override fun onComplete() { return observer.onComplete() }
override fun onSubscribe(d: Disposable) { return observer.onSubscribe(d) }
override fun onNext(t: T) { return observer.onNext(t) }
override fun onError(e: Throwable) { return observer.onError(func(e)) }
}
}
}
@Test
fun カスタムオペレータのテスト() {
Observable
.just(1)
.noOp()
.test()
.assertValues(1)
Observable
.just(1)
.myMap { it + 2 }
.test()
.assertValues(3)
Observable
.just("abc")
.myMap { it.count() }
.test()
.assertValues(3)
Observable
.just(1)
.errMap { RuntimeException(it) }
.test()
.assertValues(1)
Observable
.error<Int>(Exception())
.errMap { RuntimeException(it) }
.test()
.assertError(RuntimeException::class.java)
}
}
もう少しerrMapを作りたくなった背景を書いておきます。
Retrofit2のHttpException#response()#errorBody()のエラーレスポンスの中味を2回読む必要がありました。
しかし、OkHttp3のResponseBody#string()メソッドが破壊的なため、2回コールしたいけど1回しか許されていません。自作ExceptionでいったんResponseBodyの文字列を退避する必要に迫られ、そのときerrMapで自作Exceptionに変換したという次第です。
Kotlinの拡張関数使って、Observableのメソッドを拡張してます。