In RxJava/RxKotlin, what are the differences between returning a Completable.error(Exception()) and throwing? - error-handling

What are the differences in the following cases:
fun a(params: String) = Completable.fromAction {
if (params.isEmpty()) {
throw EmptyRequiredFieldException()
}
}
VS
fun b(params: String) = if(params.isEmpty())
Completable.error(EmptyRequiredFieldException())
else
Completable.complete()
Specifically in the context of android, if it matters (even though I don't think it does)
Thanks!

According to documentation,
If the Action throws an exception, the respective Throwable is delivered to the downstream via CompletableObserver.onError(Throwable), except when the downstream has disposed this Completable source. In this latter case, the Throwable is delivered to the global error handler via RxJavaPlugins.onError(Throwable) as an UndeliverableException.
So both of two ways you described are similar (except when the downstream has disposed). Note, that first approach (with manually throwing exception) allow to modify behavior of Completable at runtime. And second one - statically defined as you return particular type of Completable and can't modify it.
What to choose depends on your needs.

Related

Mono switchIfEmpty emitting twice

I have a scenario where i need to find a method that return a string response from external API. I have two possibilities for this response give me a valid response (with parameter 1 or parameter 2) or if both responses are not valid, return a final empty publisher to chain.
Mono<String> checkResponse(String parameter)
Check if call checkResponse(parameter1) is acceptable, ignore second call (switchIfEmpty) and continue chain, or
Check if call checkResponse(parameter2) is acceptable and continue chain, or
return Mono.Empty() and discard chain
Actually i have
checkResponse(stringArg1)
.switchIfEmpty(checkResponse(stringArg2))
.flatMapMany ...
.flatMap ...
method
public Mono<String> checkResponse(String s)
return webClient.post()
.uri(URI)
.body(BodyInserters.fromValue(s))
.retrieve()
.bodyToMono(String.class)
But switchIfEmpty is always executing.
Regards,
Are you sure that it's actually emitting twice?
There are two aspects of Project Reactor that is important to understand:
On Assembly
On Subscription
This code:
checkResponse(stringArg1)
.switchIfEmpty(checkResponse(stringArg2));
will assemble the Monos for both checkResponse calls.
In essence, the checkResponse-method is called twice - however only the Mono returned from the first checkResponse-call will be subscribed to as long as it emits an item.
You can verify this behaviour with this:
checkResponse(stringArg1)
.doOnSubscribe(s -> System.out.println("First checkResponse subscription"))
.switchIfEmpty(checkResponse(stringArg2)
.doOnSubscribe(s -> System.out.println("Second checkResponse subscription"))
);
Something that's very typical of reactive code is that top-level code within a method that returns a Mono/Flux usually executes at assembly time while all the lambdas passed to their various operators such as map/flatMap/concatMap/etc execute at subscription time.
To illustrate:
public Mono<String> getName(int id) {
// Assembly time
System.out.println("This executes at assembly time");
return userRepo.get(id)
.map(user -> {
// Subscription time
System.out.println("This executes at subscription time");
return user.name;
});
}
If assembling the Mono might be expensive while it may never be subscribed to like in your case here, you can defer assembly until subscription-time using Mono.defer:
checkResponse(stringArg1)
.switchIfEmpty(Mono.defer(() -> checkResponse(stringArg2)));
Actually there's difference between assembly time and subscription time.
Assembly time is when you create your pipeline by building the reactive chain.
Subscription time is when the execution triggered and the data starts to flow. You should consider using callbacks and lambdas since they are lazily evaluated.
So your checkResponse() method called "twice" on assembly time, because it is not a lambda, but just a regular method. And it returns Mono
You can use Mono.defer(() -> checkResponse()) and delay the execution and assembling inner mono until you subscribed.

How to inform in Kotlin that a function passed by parameter can throw an exception?

I need to inform in my class code that the function passed by parameter (convertorCall) can throw an exception.
suspend operator fun <T> invoke(
convertorCall: () -> T
): T?
For example, if this function were as a method of a class I could do this:
#Throws(JsonSyntaxException::class)
suspend fun <T> convertorCall(): T
However, as said before, I need this to be informed in the function passed by parameter of the invoke function.
I tried this:
suspend operator fun <T> invoke(
#Throws(JsonSyntaxException::class) convertorCall: () -> T
): T?
But a syntax error is generated:
This annotation is not applicable to target 'value parameter'
Kotlin doesn't have checked exceptions, i.e. ones where a function explicitly states what it could throw, and any callers are required to wrap the call in a try/catch to deal with that possibility. Or not catch it, state that they themselves might produce that exception, and pass the responsibility to handle it up the chain.
That link explains the rationale, and links to some sources talking about the issue, but it's basically just how things are done (or not done) in Kotlin. There's a #Throws annotation for interoperability with other languages where checked exceptions is how things are done, but it's not used in Kotlin itself.
If you want to inform the caller that an exception could be thrown, you're supposed to put it in the documentation comment for the function. There's a #throws tag (or an #exception one if you like) for that purpose, but like it says:
Documents an exception which can be thrown by a method. Since Kotlin does not have checked exceptions, there is also no expectation that all possible exceptions are documented, but you can still use this tag when it provides useful information for users of the class.
So it's purely informational really, and the user can choose to handle or not handle those potential exceptions - it's not required. And if you're writing your own functions, you might want to consider whether they should throw an exception to the caller at all during normal, anticipated behaviour, or if they should return some kind of error value (like null) or an error type (e.g. a sealed class that has some kind of failure subclass as well as success types).
// You could return this type instead of throwing an exception
sealed class Result<T> {
class Conversion<T>(data: T) : Result<T>()
class Error<T>(message: String) : Result<T>()
}
Basically, if you know a specific thing can go wrong during normal operation, is it really exceptional? Or just another kind of result to inform the caller about so it can take action if it needs to?

Kotlin checkNotNull vs requireNotNull

As I learn new components in Kotlin, I came accross requireNotNull and checkNotNull but the only difference I've found is that requireNotNull can throw an IllegalArgumentException while checkNotNull can throw an IllegalStateException. Is this the only reason why there are two methods, or I'm missing some under-the-hood implementation detail?
The exception types are the only practical difference, as far as the compiler is concerned — but there's a big difference in intent, for anyone reading the code:
• require…() functions are for checking parameters, to confirm that a function's input fulfils its contract. So you'd normally call them first thing in a function. (Of course, Kotlin's non-nullable types mean that you wouldn't need to call requireNotNull() for a single parameter; but you might need to check a more complex condition on a combination of parameters or their sub-objects.) That's why they throw IllegalArgumentException: it's checking that the arguments are legal.
• check…() functions are for checking the relevant properties, to confirm that the object or whatever is in a valid state for this function to be called now. (Again, any properties that were never null would be typed accordingly, so checkNotNull() is more appropriate for cases where a property, combination, and/or sub-property can be null, but this function mustn't be called when they are.) So they throw IllegalStateException: they're checking that the object's current state allows the function to be called.
In both cases, you could of course write a standard if check (as you would in Java). Or you could use the Elvis operator ?: to do the check the first time the possibly-null value is used. But these functions give you an alternative that's in a more declarative form: you'd normally put them at the top of the function, where they spell out what the function's contract is, in a way that's obvious to anyone glancing at the code.
As a linked answer points out, there are also assert…() functions, which again have more of a semantic difference than a practical one. Those are for detecting programming errors away from the boundary of a function call: for confirming invariants and other conditions, and for all the checks in unit tests and other automated tests.
(Assertions have another important difference: they can be enabled and disabled from the command-line. Though in my experience, that's not a very good thing. If a check is important, it should always be run: be mandatory; if not, then it should be removed, or at least moved to automated tests, once the code is debugged.)
It is a semantic difference and hence it throws different exceptions. RequireNotNull is used to check input values, typically at the beginning of a method, while checkNotNull is used anywhere to check the current state.
If you're looking for differences in implementation, the best place to go would be the source code. In this case it seems like there are no differences aside from the different exception thrown, the source for both methods is otherwise identical.
checkNotNull
[...]
if (value == null) {
val message = lazyMessage()
throw IllegalStateException(message.toString())
} else {
return value
}
requireNotNull
[...]
if (value == null) {
val message = lazyMessage()
throw IllegalArgumentException(message.toString())
} else {
return value
}
Therefore the difference is purely semantic. The answer from #gidds details some good scenarios for using them both.

JacksonSerializer doesn't work in Kotlin Lambda

When I create a client with the JacksonSerializer() feature and make some API calls, then run that script on my local machine, I get no error and the script runs successfully. However, when I upload this script as an AWS Lambda, I get the following error:
com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of kotlin.coroutines.Continuation, problem: abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information
At first, I thought the error originated from me constructing the client outside of the Handler class, but when I made the client a private value inside the Handler class, I still get the error. I've included println() statements in my function, but they don't even run. That tells me that my handleRequest() funciton isn't getting run. Is there some AWS/Lambda'ism that prevents me from using the JacksonSerializer() feature as? If so, are there any alternatives on how to parse JSON responses with the Ktor client?
My client construction:
private val client = HttpClient(Apache) {
install(JsonFeature) {
serializer = JacksonSerializer()
}
}
An example call using the client:
val response = client.post<JsonNode> {
url(URL(GITHUB_GRAPHQL_ENDPOINT))
body = reqBody
headers {
append("Authorization", "bearer $token")
}
}
I'm guessing that you made your handler function be a kotlin suspend function? If so, that's your problem.
When you mark a function suspend, the compiler applies a bunch of magic. Most of the time, you don't need to know anything about this, other than the fact that any suspend function gets an extra parameter of type kotlin.coroutines.Continuation added to its signature. You usually don't notice this, since the compiler also makes calls to the function pass along their own hidden Continuation parameter.
Continuation, by design, can't be created by a tool like Jackson - it's an internal thing. What you probably need to do (assuming that you did make your handler function suspend) is to wrap your method in runBlocking {} and make it not be a suspend function. It's probably easiest to create a new handler, like so:
fun fixedHandler(input: MyInput, context: Context) = runBlocking {
originalHandler(input, context)
}
suspend fun originalHandler(input: MyInput, context: Context): MyOutput {
TODO("This is your original code")
}
PS - I've usually found it best to leverage the pre-defined Lambda interfaces to write my Lambda functions - it prevents you from encountering issues like this. See https://docs.aws.amazon.com/lambda/latest/dg/java-handler-using-predefined-interfaces.html for how to do it.
Have you checked out your dependencies running locally versus your dependencies in AWS? I've had issues where locally I'm running with a version, but the version in AWS was different. That could especially explain the error about continuations... Perhaps the method signature is different in whatever version you're using?
Look especially for provided scopes in your gradle/maven pom. Those are easy places for version to be out of sync.

How to handle the null scenario with kotlinx-coroutines-reactive?

kotlinx-coroutines-reactive makes org.reactivestreams.Publisher to have awaitXXX methods:
val person = peopleReactiveRepository.findById(personId).awaitSingle()
If there is no person can be found by a person ID, this invocation will throw NoSuchElementException and this exception cannot be handled in the user code directly. And Spring MVC ExceptionHandler can not translate this exception into a user-friendly response.
java.util.NoSuchElementException: No value received via onNext for awaitSingle
at kotlinx.coroutines.experimental.reactive.AwaitKt$awaitOne$$inlined$suspendCancellableCoroutine$lambda$1.onComplete(Await.kt:131) ~[kotlinx-coroutines-reactive-0.22.1.jar:na]
at reactor.core.publisher.StrictSubscriber.onComplete(StrictSubscriber.java:123) ~[reactor-core-3.1.2.RELEASE.jar:3.1.2.RELEASE]
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onComplete(Operators.java:1327) ~[reactor-core-3.1.2.RELEASE.jar:3.1.2.RELEASE]
at reactor.core.publisher.FluxHide$SuppressFuseableSubscriber.onComplete(FluxHide.java:137) ~[reactor-core-3.1.2.RELEASE.jar:3.1.2.RELEASE]
at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:130) ~[reactor-core-3.1.2.RELEASE.jar:3.1.2.RELEASE]
at reactor.core.publisher.MonoNext$NextSubscriber.onComplete(MonoNext.java:96) ~[reactor-core-3.1.2.RELEASE.jar:3.1.2.RELEASE]
at com.mongodb.reactivestreams.client.internal.ObservableToPublisher$1.onComplete(ObservableToPublisher.java:78) ~[mongodb-driver-reactivestreams-1.6.0.jar:na]
One of approaches I can figure out is in the following:
val person = peopleRepository.findById(personId).awaitFirstOrDefault(null)
if (person == null) {
// do something
}
But I do not think it is an elegant way. For example, can provide a method named awaitSingleOptional.
Is there any better Kotlin way to handle this scenario?
There are no standard Optional wrappers in Kotlin. You can use the let function for such cases:
val person = peopleRepository.findById(personId).awaitFirstOrDefault(null)?.let {
// do
}
If the await-expression evaluates to the default null, the let invocation will also evaluate to null. If you need to handle this case, the Elvis operator can be used:
.let {...} ?: throw IllegalStateException()
An Extension awaitFirstOrNull() has been made available in the recent kotlinx.coroutines release 0.22.2. See this PR.
Taken from the release notes:
Reactive: Added awaitFirstOrDefault and awaitFirstOrNull extensions (see #224, PR by #konrad-kaminski).
You can definitely use Optional wrappers if you are programming in a functional way.
If you want to get your toes wet with functional programming, you can pick up Arrow which has the Option and the Try data types for this purpose.
Using ?.let is another option but it won't help you much with reactive programming.
There is also the Notification class in ReactiveX which will lets you handle an erroneous scenario if you are doing Railway Oriented Programming.