1

To start I have the following Moshi json.

@JsonClass(generateAdapter = true)
data class OrderDetails(
    @Json(name = "_id") val id: Int,
    @Json(name = "status") val status: String,
    @Json(name = "tableNo") val tableNo: Int,
    @Json(name = "serverId") val serverId: Int?,
    @Json(name = "items") val orderItems: List<OrderDetailsItem>
)

All these fields are expected to have data except for serverId. This data is fetched from the server where I can allow the user to select order.

onSeletedOrder
   .map { it.orderDetails.serverId } //blows up here apparently.
   .filterNotNull() //have tried this but it doesn't matter.
   .flatMap { findServerBy(it) }
   .map { "${it.firstname} ${it.lastname}" }

When I map to the serverId above I blow up with an NPE. It's interesting that the map (even though it is optional) does an unsafe cast afterwards. I'd expect it to maintain the optional-ness after the map. I'm assuming this is because of the bridging backwards to RxJava. Curious if anyone has a further explanation on why this is.

3
  • Null valuess are not allowed in RxJava so map to null is forbidden and crashes with NPE. You could prefilter with filter { it.orderDetails.serverId != null } before the map. As for why map doesn't result in type Optional<T> in Kotlin, I have no idea. Commented Nov 28, 2019 at 17:06
  • What is the type of onSeletedOrder: Observable<OrderDetails>? Single? Something else? Commented Nov 29, 2019 at 7:24
  • The type is a PublishSubject<OrderDetails> Commented Nov 29, 2019 at 13:47

3 Answers 3

1

RxJava does not allow nulls inside the stream. Ideally you would perform this filter before the items enter the stream, but if you can't do that one workaround you could get away with is to use an empty string in place of null.

onSeletedOrder
   .map { it.orderDetails.serverId.orEmpty() }
   .filter { it.isNotEmpty() }
   .flatMap { findServerBy(it) }
   .map { "${it.firstname} ${it.lastname}" }
Sign up to request clarification or add additional context in comments.

1 Comment

I'm not happy with the feedback given with the extra defensive-ness need but this works. I suppose I can do the filter even earlier than the map. So filter { it.orderDetails.serverId != null } then map { it.orderDetails.serverId }
0

For "map, but exclude some elements", RxJava has flatMapMaybe (other types than Observable can also have it with corresponding return type):

// helper
fun <T> T?.toMaybe(): Maybe<T> = if (this != null) Maybe.just(this) else Maybe.empty<T>

onSeletedOrder
   .flatMapMaybe { it.orderDetails.serverId.toMaybe() }
   .flatMap { findServerBy(it) }
   .map { "${it.firstname} ${it.lastname}" }

Comments

0

The best approach is to format your Data Class with optional data.

@JsonClass(generateAdapter = true)
data class OrderDetails(
    @Json(name = "_id") val id: Int? = 0,
    @Json(name = "status") val status: String? = "Not active",
    @Json(name = "tableNo") val tableNo: Int? = 0,
    @Json(name = "serverId") val serverId: Int? = 0,
    @Json(name = "items") val orderItems: List<OrderDetailsItem>? = listOf()
)

You won't receive any NPE

3 Comments

Thats actually not the case when I start putting these particular optional-fields into RxJava.
Interesting, I found that moshi doesn't support this, based on this github.com/square/moshi/issues/807 Can you experiment a bit and use, Kotlinx Serialization. I have been using it in my project and this use case is coverd. Just wanted to see, if it would work with RxJava map filter
I'll take a look at it, but fundamentally as I've researched this, there is no null safety in RxJava streams. It would take a rewrite in order to accommodate from what I've gathered of RxJava. This was a good thread which discussed some of the issues/differences (github.com/reactor/reactor-core/issues/979)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.