What is the idiomatic way to work with nulls in Spring Reactor and Kotlin? - kotlin

I have a Flux of strings that should be converted to a Flux of dto. Parsing can be finished with an error and by the business rules I just need to skip such entries
If I use "Kotlin's" null - I got NPE because by design reactor doesn't accept nulls in .map
fun toDtoFlux(source:Flux<String>):Flux<Dto>{
source.map(Parser::parse)
.filter(it!=null)
}
object Parser{
fun parse(line:String):Dto?{
..
}
}
I can use Optional. But it is not a Kotlin way.
fun toDtoFlux(source:Flux<String>):Flux<Dto>{
source.map(Parser::parse)
.filter(Optional.isPresent)
.map(Optional::get)
}
object Parser{
fun parse(line:String):Optional<Dto>{
..
}
}
What is the most idiomatic way to handle such cases in Kotlin?

You can create an extension function:
fun <T, U> Flux<T>.mapNotNull(mapper: (T) -> U?): Flux<U> =
this.flatMap { Mono.justOrEmpty(mapper(it)) }
Then you can use it like this:
fun main() {
Flux.just("a", "b", "c")
.mapNotNull { someNullableMapFunction(it) }
.doOnNext { println(it) } // prints "a" and "c"
.blockLast()
}
fun someNullableMapFunction(it: String): String? {
if (it == "b") {
return null
}
return it
}
UPDATE
Based on Simon's comment extension function implementation might be more idiomatic (and performant?) in Reactor this way:
fun <T, U> Flux<T>.mapNotNull(mapper: (T) -> U?): Flux<U> =
this.handle { item, sink -> mapper(item)?.let { sink.next(it) } }

The solutions I see :
Using Reactor API
I'd suggest you to use Reactor API to address such case, and make your parser return a Mono. The empty Mono represents the absence of result. With that, you can use flatMap instead of chaining map/filter/map.
It may seem a little overkill like that, but it will allow any parser implementation to do async stuff in the future if needed (fetching information from third-party service, waiting validation from user, etc.).
And it also provide a powerful API to manage parsing errors, as you can define backoff/custom error policies on parsing result.
That would change your example like that :
fun interface Parser {
fun parse(record: String): Mono<Dto>;
}
fun Parser.toDtoFlux(source:Flux<String>): Flux<Dto> {
source.flatMap(this::parse)
}
Using sealed class
Kotlin offers other ways of managing result options, inspired by functional programming. One way is to use sealed classes to desing a set of common cases to handle upon parsing. It allows to model rich results, giving parser users multiple choices to handle errors.
sealed class ParseResult
class Success(val value: Dto) : ParseResult
class Failure(val reason : Exception) : ParseResult
object EmptyRecord : ParseResult
fun interface Parser {
fun parse(raw: String) : ParseResult
}
fun Parser.toDtoFlux(source:Flux<String>): Flux<Dto> {
return source.map(this::parse)
.flatMap { when (it) {
is Success -> Mono.just(it.value)
is Failure -> Mono.error(it.reason) // Or Mono.empty if you don't care
is EmptyRecord -> Mono.empty()
}}
}

Related

Custom Gradle Task having Kotlin Delegate

Gradle tasks using Kotlin are implemented as either abstract class ... or interface ....
In either case it is not clear how to use delegation.
The following works correctly but requires delegation to be performed manually (i.e. it does not use Kotlin delegation).
#CacheableTask
abstract class FooTask : DefaultTask(), CopySourceSpec {
#get:InputFiles
#get:Optional
#get:SkipWhenEmpty
#get:IgnoreEmptyDirectories
#get:PathSensitive(PathSensitivity.RELATIVE)
abstract val sourceFiles: ConfigurableFileCollection
#TaskAction
fun canonize() {
val sourceFileTree = sourceFiles.asFileTree
// do something with the sourceFileTree
}
override fun from(vararg sourcePaths: Any?): ProtobufHeaderTask {
this.sourceFiles.from(sourcePaths)
return this
}
override fun from(sourcePath: Any, closure: Closure<*>): ProtobufHeaderTask {
this.sourceFiles.from(sourcePath, closure)
return this
}
override fun from(sourcePath: Any, configureAction: Action<in CopySpec>): ProtobufHeaderTask {
this.sourceFiles.from(sourcePath, configureAction)
return this
}
}
It seems like this could be done more simply using Kotlin delegation.
#CacheableTask
abstract class FooTask : DefaultTask(), ConfigurableFileCollection by sourceFiles {
#get:InputFiles
#get:Optional
#get:SkipWhenEmpty
#get:IgnoreEmptyDirectories
#get:PathSensitive(PathSensitivity.RELATIVE)
abstract val sourceFiles: ConfigurableFileCollection
#TaskAction
fun canonize() {
val sourceFileTree = sourceFiles.asFileTree
// do something with the sourceFileTree
}
}
This latter case produces an error that sourceFiles is not defined.
Is it possible to use Kotlin delegation in this way?

How can I access the context in every function of a call chain with Kleisli?

I have a call chain of some methods, where I pass a context via a Kleisli. Basically I want to pass a context down to the db access layer, but I want to access this context everywhere in between.
The following example works perfectly. My problem though is, that I want to access the context in OrderService.findAll(...) as well. I tried several approaches but I keep failing.
object OrderRepository {
fun findAll(userId: String): Kleisli<Context, ForIO, List<Order>> =
Kleisli { ctx ->
IO {
ctx.db.query("someQuery")
}
}
}
object OrderService {
fun findAll(userId: String): Kleisli<Context, ForIO, List<OrderResponse>> =
OrderRepository.findAll(userId).map(IO.monad()) { orderList ->
orderList.map {
//Create OrderResponse from Order
}
}
}
Is it possible to access the context there, or doesn't this make any sense? Thanks for the help :)
what you need is a Kleisli from D to D, with D as the Context. That way you would have D (context) as the result type also, and you'd be able to flatMap and get access to it. That is why the method ask() provides, available over the companion.
Let's say your OrderRepository is also a dependency in the Context instead of a pure function (for the sake of the example), so you need to access it from within the context in the service. See:
interface OrderApi
interface OrderDB {
fun query(query: String): List<Order> = TODO()
}
data class Order(val id: String)
data class OrderResponse(val order: Order)
data class Context(val api: OrderApi, val repository: OrderRepository, val db: OrderDB)
class OrderRepository {
fun findAll(userId: String): Kleisli<Context, ForIO, List<Order>> =
Kleisli { ctx ->
IO {
ctx.db.query("someQuery")
}
}
}
object OrderService {
fun findAll(userId: String): Kleisli<Context, ForIO, List<OrderResponse>> {
val monad = IO.monad()
return Kleisli.ask<Context, ForIO>(monad).flatMap(monad) { ctx ->
ctx.repository.findAll(userId).map(monad) { orderList ->
orderList.map { OrderResponse(it) }
}
}
}
}
That said, Kleisli is a Monad transformer (also called ReaderT) that can be a bit convoluted to work with. If you want to inject dependencies on a functional codebase and stay simpler, my advice is to go for extension functions over a Context receiver, which already implicitly passes your dependencies across al levels, which is described on this post by Paco.
#brewcode #bob there is a higher-order pattern in FP above the kinds of encodings like MTL and that is delimited continuations, the mother of all monads. That subsumes to imperative syntax the entire Functor hierarchy including monads like readers bringing application syntax to the environment through continuations. This is what kotlin suspension is.
#Jorge Castillo question is right but any lang with continuations support has better abstractions than wrapping in data types at allocation cost.
For JS and TS instead of the Haskell like encoding that ReaderT or any callback style encoding like the ones Scala and Haskell propose one based on delimited continuations if there is a way in those languages would be much cleaner and easier to use to beginners than wrapped callback style as ReaderT proposes. Look at the program below and see if this has any drawbacks over the wrapped version.
interface OrderApi
interface OrderDB {
fun query(query: String): List<Order> = TODO()
}
data class Order(val id: String)
data class OrderResponse(val order: Order)
data class Context(
val api: OrderApi,
val repository: OrderRepository,
val db: OrderDB) : OrderApi by api, OrderRepository by repository, OrderDB by db
interface OrderRepository {
suspend fun Context.findAll(userId: String): List<Order> =
query("someQuery")
}
object OrderService {
suspend fun Context.findAll(userId: String): List<OrderResponse> =
findAll(userId).map(::OrderResponse)
}

Getting a list of annotated functions in Kotlin using reflection

I am new to Kotlin and I want to do the following:
Annotate some functions with an annotation e.g "Executable"
At runtime, get all the functions with this annotation
Inspect a property on the annotation and if it matches a condition, invoke the function
I have the following code
annotation class Executable(val name : String)
#Executable("doSomething")
fun stepDoSomething (param1 : String) {
println("I am a step that does something! I print $param1")
}
However, I am unclear on how to retrieve all functions with the Executable annotation at runtime and inspect them.
Thank you for your help!
To accomplish this, you will need to use a classpath scanner, such as ClassGraph. Classpath scanners offer APIs to find classes based on various criteria, such as what package they’re in, what interface they implement, or what annotations they have. In the case of ClassGraph, the ScanResult has a getClassesWithMethodAnnotation(String name) method. Once you have all of those classes, you can use ordinary reflection to find which method(s) in those classes have the specific annotation you’re looking for and inspect the properties of the annotations. Here is a good overview of how to create an annotation and inspect it using reflection.
Here is my implementation based on (very helpful) Matthew Pope's answer:
import io.github.classgraph.ClassGraph
import kotlin.reflect.KClass
import kotlin.reflect.KFunction
import kotlin.reflect.jvm.kotlinFunction
#Image(filename = "image-1.svg")
fun foo() {
println("in foo")
}
#Image(filename = "image-2.svg")
fun bar() {
println("in bar")
}
#Throws(Exception::class)
fun getAllAnnotatedWith(annotation: KClass<out Annotation>): List<KFunction<*>> {
val `package` = annotation.java.`package`.name
val annotationName = annotation.java.canonicalName
return ClassGraph()
.enableAllInfo()
.acceptPackages(`package`)
.scan().use { scanResult ->
scanResult.getClassesWithMethodAnnotation(annotationName).flatMap { routeClassInfo ->
routeClassInfo.methodInfo.filter{ function ->
function.hasAnnotation(annotation.java) }.mapNotNull { method ->
method.loadClassAndGetMethod().kotlinFunction
// if parameter needed:
// method.getAnnotationInfo(routeAnnotation).parameterValues.map { it.value }
}
}
}
}
fun main(args: Array<String>) {
getAllAnnotatedWith(Image::class)
.forEach { function ->
function.call()
}
}

Kotlin functional way

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.

Why is subtype function overloading not possible with Kotlin sealed classes?

Let's say I have sealed class I'm using for a server response:
sealed class Response{
class Success: Response()
class ErrorA: Response()
class ErrorB: Response()
}
And a bogus response:
fun getResponse(): Response{
val r = Random()
return when (r.nextInt(3)) {
0 -> { Response.Success() }
1 -> { Response.ErrorA() }
2 -> { Response.ErrorB() }
else -> { throw IllegalStateException() }
}
}
And I want to handle the response. I currently could use something like this:
fun handle(response: Response) = when (response) {
is Response.Success -> { handle(response) }
is Response.ErrorA -> { handle(response) }
is Response.ErrorB -> { handle(response) }
}
Which the compiler will then ensure handles all cases. An awesome feature!
Why, though, could I not do something like this:
class ResponseHandler(){
fun handle(success: Response.Success) {}
fun handle(error: Response.ErrorB) {}
fun handle(error: Response.ErrorA) {}
}
and call
ResponseHandler().handle(response)
This achieves the same thing but does not compile, my question is this: in the same way that the compiler ensures, at runtime, that all cases are handled in a when statement, why can the same logic not be applied to method overloading?
Any information or referrals to further reading would be hugely helpful. Thanks
In principle it could be done (essentially by auto-generating the handle(response: Response) = when ... method). But I don't think it's ever likely to be. Overloading in Kotlin works basically the same as in Java/Scala/other JVM languages and introducing a major difference for so little benefit doesn't looks like a good idea (of course this doesn't apply to when which is Kotlin-specific).
If you want it, you can just define the same fun handle(response: Response) inside ResponseHandler (and make the other handle methods open so it's actually useful).
This problem can be broke down to this simplified example:
fun calc(i: Int) = i * 2
fun calc(d: Double) = d * 2
fun main(args: Array<String>) {
val i: Number = 5
calc(i)
}
You have two specialized methods that take an Int and Double respectively. Your value is of type Number (supertype of both, Int and Double). Although i obviously is an integer, your variable has a type Number, which cannot be an argument to either calc(i: Int) or calc(d: Double).
In your case, you get a Response and want to invoke one of the overloaded methods, none of which takes a Response directly.