Description
Enhancement Description
The current query extension methods return values using Java's CompletableFuture
and Optional
types. The usage of these types seems awkward to me in modern Kotlin that uses coroutines. This enhancement request is to encapsulate the use of Java types in favor of pure Kotlin idioms.
Current Behaviour
Note the use of Java types here, for example:
inline fun <reified R, reified Q> QueryGateway.queryOptional(query: Q): CompletableFuture<Optional<R>> {
return this.query(query, ResponseTypes.optionalInstanceOf(R::class.java))
}
This requires the developer to adapt CompletableFuture
to Kotlin's Deferred
or Flow
types (depending on single vs multiple response types), as well as adapting Optional
to Kotlin's nullable type system.
Wanted Behaviour
I've been trying to create new extension methods that only expose Kotlin types.
Consider the following:
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.future.asDeferred
import java.util.Optional
import java.util.concurrent.CompletableFuture
fun <T> Optional<T>.orNull(): T? = orElse(null)
fun <T> CompletableFuture<Optional<T>>.asDeferredOfNullable(): Deferred<T?> = thenApply { it.orNull() }.asDeferred()
Now, notice how I use them in the extension method queryNullableAsDeferred
below, where Schedule
is a Spring Data MongoDB persistent entity on the read side:
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.future.asDeferred
import org.axonframework.commandhandling.gateway.CommandGateway
import org.axonframework.extensions.kotlin.queryOptional
import org.axonframework.queryhandling.QueryGateway
import org.springframework.stereotype.Component
// note use of Kotlin async types here
inline fun <reified R, reified Q> QueryGateway.queryNullableAsDeferred(q: Q): Deferred<R?> =
queryOptional<R, Q>(q).asDeferredOfNullable()
@Component
class CqrsSchedulingService(val cgw: CommandGateway, val qgw: QueryGateway) {
fun createSchedule(cmd: CreateScheduleCommand): Deferred<Unit> {
return cgw.send<Unit>(cmd).asDeferred() // note conversion to Deferred here
}
fun updateSchedule(cmd: UpdateScheduleCommand): Deferred<Unit> {
return cgw.send<Nothing>(cmd).asDeferred() // note conversion to Deferred here
}
fun findScheduleById(q: FindScheduleByIdQuery): Deferred<Schedule?> { // note use of Deferred and Kotlin's ? nullable type operator
return qgw.queryNullableAsDeferred(q) // note use of extension method here
}
}
I'm no Kotlin expert yet, so maybe this needs some fine-tuning, but this seems more natural to me. I think this issue could be expanded to other parts of the codebase as well (like CommandGateway.send(..)
, as they also return CompletableFuture
.