I am trying to use Kotlin runCatching feature along with response + error translation functions. Something like
class SomeClassThatCallsServiceX {
fun remoteCall(input): TransformedResult {
kotlin.runCatching{ serviceX.call(input)}
.onSuccess { return functionToTranslateServiceXResponse(it)}
.onFailure{ throw functionToranslateServiceXError(it)}
}
}
functionToTranslateServiceXResponse : (OriginalResult) -> TransformedResult
functionToranslateServiceXError : (Throwable) -> RuntimeException
However Kotlin is giving me the following error - A 'return' expression required in a function with a block body ('{...}'). If you got this error after the compiler update, then it's most likely due to a fix of a bug introduced in 1.3.0 (see KT-28061 for details)
Running with Kotlin 1.4.
I am still new to Kotlin- wondering if I am doing something fundamentally wrong here. Any help would be greatly appreciated.
Update: tried the following pattern, basic test cases seem to be working fine. Would love to know what others think of the pattern
class SomeClassThatCallsServiceX {
fun remoteCall(input): TransformedResult {
return kotlin.runCatching{ serviceX.call(input)}
.mapCatching(functionToTranslateServiceXResponse)
.onFailure(functionToranslateServiceXError)
.getOrThrow()
}
}
functionToTranslateServiceXResponse : (OriginalResult) -> TransformedResult
functionToranslateServiceXError : (Throwable) -> Unit
I think there are couple of issues here:
class SomeClassThatCallsServiceX {
// You are not returning `TransformedResult` but Result<TransformedResult>
// but Result cannot be returned by kotlin https://stackoverflow.com/q/52631827/906265
fun remoteCall(input) {
// error mentioned that "return" was missing but you cannot return Result
kotlin.runCatching{ serviceX.call(input)}
.onSuccess { return functionToTranslateServiceXResponse(it) }
.onFailure{ throw functionToranslateServiceXError(it) }
}
}
Having a callback could be a solution (pseudocode):
fun remoteCall(input Any, callback: Callback) {
kotlin.runCatching{ serviceX.call(input)}
.onSuccess { callback.success(it) }
.onFailure { callback.error(it) }
}
Have a tiny example on Kotlin Playground website based on the above https://pl.kotl.in/W8wMDEzN1
Related
I have List<Result<String>> and I would like to convert it to Result<List<String>>. I understand that List<Result<String>> could have both failure and successful results but I would like to terminate in the first failure.
If you want to have a failure as soon there is one Result that is a failure you can do this :
fun <T> List<Result<T>>.toResult() = if (any { it.isFailure }) {
Result.failure<List<Result<Any>>>(Throwable("A result has errors"))
} else {
Result.success(map { it.getOrNull() })
}
With this code, you get a failure as soon as there is one value has a failure.
Or if you don't care handling the error yourself :
fun <T> List<Result<T>>.toResult() = runCatching {
Result.success(map { it.getOrThrow() })
}
In most libraries this function is known as sequence.
Kotlin's Arrow library implements it for its implementation of the type Either, which is a generalization of Result: https://arrow-kt.io/docs/apidocs/arrow-core/arrow.core/sequence.html
With Arrow's Either you would write:
val xs: List<Result<String>> = ...
val ys: Result<List<String>> = xs.sequence()
The Kotlin stdlib does not seem to have it. You could define it as an extension method using getOrThrow, catching any thrown Throwable and wrapping in a Resultagain:
fun <T> List<Result<T>>.sequence(): Result<List<T>> = try {
Result.success(this.map { it.getOrThrow() })
}
catch (e:Throwable) { Result.failure(e) }
I'm trying to perfect myself in Kotlin with functional programming. And then I did this:
I was tired of the way I write try - catch, and created the following function:
package com.learning.functionalway
fun <T> tryCatch(t: T?, excpetion: (Throwable)): T? = try {
t
} catch (e: Exception) {
throw excpetion
}
And I used it like this:
#Service
class ProductService(val repository: IProductRepository, val repositoryS: IStockRepository) : IService<Product, ProductModel> {
override fun find(id: Long) = tryCatch(
repository.find(id),
DataNotFound("Product not found"))
other methods ..
}
And my exception that I deal in the "Exception Handler"
class DataNotFound(message: String?) : Exception(message) {
}
Is this a correct way I used to modify the way I use try - catch?
Or are there better ways to do it?
Your solution is not a "more functional" way of doing error handling but rather just arguably a slight improvement in try-catch syntax.
If you truly want to embrace functional programming, I'd recommend you to check out Arrow. The standard Kotlin library is not enough for advanced functional programming concepts (such as error handling) and Arrow fills that gap.
You can read their documentation on how to do proper error handling.
If you fancy a talk about it, I'd recommend you to check out this video (topic of error handling starts here) which is about Kotlin and functional programming.
One way to remake the try-catch syntax to make it more functional is like this:
sealed class Try<out Output> {
class Some<Output>(val output: Output) : Try<Output>()
class None(val exception: Exception) : Try<Nothing>()
companion object {
operator fun <Output> invoke(toTry: () -> Output) = try {
Some(toTry())
} catch (e: Exception) {
None(e)
}
}
val value get() = when(this) {
is Some -> output
is None -> null
}
infix fun catch(onException: (Exception) -> Unit): Output? = when (this) {
is Some -> output
is None -> {
onException(exception)
null
}
}
}
class ProductService(val repository: IProductRepository, val repositoryS: IStockRepository) : IService<Product, ProductModel> {
override fun find(id: Long): Product? = Try {
repository.find(id)
} catch { exception ->
println("Error trying to get product $exception")
}
//other methods ..
}
The key advantage here is that unlike in the original syntax you can do things by parts. So if you have a lot of tries to do and want to handle all the results at the end, with this syntax you can.
Today I stumbled across a situation which I do not understand, possibly because of lack of insight into how mockito and mockito-kotlin work internally.
Given the code below, from my Kotlin beginner perspective, I have two pretty similar interface-methods. One returns Boolean, one String. Both are suspend functions in my example as in my real world situation my functions are too.
class ITestInterface {
suspend fun returnBoolean(): Boolean {
return true
}
suspend fun returnSomeString() : String {
return "String"
}
}
#Test
fun demoTest() {
val implMock = mock<ITestInterface> {
on {
runBlocking {
returnSomeString()
}
} doReturn "Hello"
on {
runBlocking {
returnBoolean()
}
} doReturn false
}
}
My observation is, when I run the test, like depicted above, I get the following error Message
com.nhaarman.mockitokotlin2.MockitoKotlinException: NullPointerException thrown when stubbing.
This may be due to two reasons:
- The method you're trying to stub threw an NPE: look at the stack trace below;
- You're trying to stub a generic method: try `onGeneric` instead.
at com.nhaarman.mockitokotlin2.KStubbing.on(KStubbing.kt:72)
at com.rewedigital.fulfillment.picking.components.substitute.DemoTest.demoTest(DemoTest.kt:30)
[...]
Experiments showed that
the behavior is only shown by the Boolean returning function, not by returnSomeString()
removing the suspend keyword fro the returnBoolean function makes the error go away
using onGeneric as suggested in the error message also makes the error go away
Could anybody explain why this is happening? To what extend do we have to do with generics here? And what would be the correct way of solving the issue in our real application? Having a bunch of on {} and some onGeneric {} ?
Thanks for your help!
You should use the onBlocking method to properly mock the suspend function
Please try the following code:
#Test
fun demoTest() {
val implMock = mock<ITestInterface> {
onBlocking {
returnSomeString()
} doReturn "Hello"
onBlocking {
returnBoolean()
} doReturn false
}
runBlocking {
// Execute your code here
assertThat(implMock.returnSomeString()).isEqualTo("Hello")
assertThat(implMock.returnBoolean()).isEqualTo(false)
}
}
I am using io.vertx.reactivex.kafka.client.producer.KafkaProducer client. The client has a
rxWrite function which returns Single<RecordMetadata>. However I need to log error if any, during write operation. It apparently is not getting executed.
I have written following working example.
test(): Function to test the chaining and logging
fun test(): Single<Int> {
val data = Single.just(ArrayList<String>().apply {
add("Hello")
add("World")
})
data.flattenAsObservable<String> { list -> list }
.flatMap { advertiser ->
//does not work with writeKafka
writeError(advertiser).toObservable().doOnError({ println("Error $data") })
}
.subscribe({ record -> println(record) }, { e -> println("Error2 $e") })
return data.map { it.size }
}
writeKafka: Writes the given given string into Kafka and returns Single
fun writeKafka(param: String): Single<RecordMetadata> {
//null topic to produce IllegalArgumentException()
val record = KafkaProducerRecord.create(null, UUID.randomUUID().toString(), param)
return kafkaProducer.rxWrite(record)
}
writeError: Always return a single with error of same type
fun writeError(param: String): Single<RecordMetadata> {
return Single.error<RecordMetadata>(IllegalArgumentException())
}
So when I call writeKafka It only prints Error2 but if I use writeError it prints both Error and Error2. Looks like the single returned by writeKafka is still waiting for result, but then why even Error2 is printed?
I am pretty newbie in RxJava2, could somebody point out any error in that?
It is important to read and post the stacktrace of errors so that the problem can be isolated.
In this case, looks like you get the IllegalArgumentException from create and you don't get any Single because the relevant Kafka class throws it. return kafkaProducer.rxWrite(record) never executes at all and you practically crash the flatMap. doOnError never gets into play hence only the "Error2" is printed.
When I tried to write an equivalent of a Java try-with-resources statement in Kotlin, it didn't work for me.
I tried different variations of the following:
try (writer = OutputStreamWriter(r.getOutputStream())) {
// ...
}
But neither works. Does anyone know what should be used instead?
Apparently Kotlin grammar doesn't include such a construct, but maybe I'm missing something. It defines the grammar for a try block as follows:
try : "try" block catchBlock* finallyBlock?;
There is a use function in kotlin-stdlib (src).
How to use it:
OutputStreamWriter(r.getOutputStream()).use {
// `it` is your OutputStreamWriter
it.write('a')
}
TL;DR: No special syntax, just a function
Kotlin, as opposed to Java, does not have a special syntax for this. Instead, try-with-resources, is offered as the standard library function use.
FileInputStream("filename").use { fis -> //or implicit `it`
//use stream here
}
The use implementations
#InlineOnly
public inline fun <T : Closeable?, R> T.use(block: (T) -> R): R {
var closed = false
try {
return block(this)
} catch (e: Exception) {
closed = true
try {
this?.close()
} catch (closeException: Exception) {
}
throw e
} finally {
if (!closed) {
this?.close()
}
}
}
This function is defined as a generic extension on all Closeable? types. Closeable is Java's interface that allows try-with-resources as of Java SE7.
The function takes a function literal block which gets executed in a try. Same as with try-with-resources in Java, the Closeable gets closed in a finally.
Also failures happening inside block lead to close executions, where possible exceptions are literally "suppressed" by just ignoring them. This is different from try-with-resources, because such exceptions can be requested in Java‘s solution.
How to use it
The use extension is available on any Closeable type, i.e. streams, readers and so on.
FileInputStream("filename").use {
//use your stream by referring to `it` or explicitly give a name.
}
The part in curly brackets is what becomes block in use (a lambda is passed as an argument here). After the block is done, you can be sure that FileInputStream has been closed.
Edit: The following response is still valid for Kotlin 1.0.x. For Kotlin 1.1, there is support a standard library that targets Java 8 to support closable resource pattern.
For other classes that do not support the "use" function, I have done the following homemade try-with-resources:
package info.macias.kotlin
inline fun <T:AutoCloseable,R> trywr(closeable: T, block: (T) -> R): R {
try {
return block(closeable);
} finally {
closeable.close()
}
}
Then you can use it the following way:
fun countEvents(sc: EventSearchCriteria?): Long {
return trywr(connection.prepareStatement("SELECT COUNT(*) FROM event")) {
var rs = it.executeQuery()
rs.next()
rs.getLong(1)
}
}
I will highly recommend to use AutoCloseable for classes.
AutoCloseable object is called automatically when exiting a
try-with-resources block for which the object has been declared in the
resource specification header.
Example:
class Resource : AutoCloseable {
fun op1() = println("op1")
override fun close() = println("close up.")
}
in main function:
Resource().use {
it.op1()
}
Output:
> op1
close up.
Since this StackOverflow post is near the top of the current search results for "kotlin closeable example," and yet none of the other answers (nor the official docs) clearly explain how to extend Closeable (a.k.a. java.io.Closeable), I thought I'd add an example of how to make your own class that extends Closeable. It goes like this:
import java.io.Closeable
class MyServer : Closeable {
override fun close() {
println("hello world")
}
}
And then to use it:
fun main() {
val s = MyServer()
s.use {
println("begin")
}
println("end")
}
See this example in the Kotlin Playground here.