Javalin RFCs
Various experimental extensions to Javalin 4.x used in Reposilite 3.x. Provides basic support for Kotlin coroutines and async routes with a set of useful utilities.
repositories {
maven { url 'https://repo.panda-lang.org/releases' }
}
dependencies {
val version = "1.0.8"
implementation "com.reposilite.javalin-rfcs:javalin-context:$version"
implementation "com.reposilite.javalin-rfcs:javalin-reactive-routing:$version"
}
Project also includes panda-lang :: expressible library as a dependency. It’s mainly used to provide Result<VALUE, ERROR>
type and associated utilities.
Reactive Routing
Experimental router plugin that supports generic route registration with custom context and multiple routes within the same endpoints.
<div class="highlight highlight-source-kotlin position-relative" data-snippet-clipboard-copy-content="// Custom context
class AppContext(val context: Context)
// Some dependencies
class ExampleFacade
// Endpoint (domain router)
class ExampleEndpoint(private val exampleFacade: ExampleFacade) : AbstractRoutes() {
private val sync = route("/sync", GET, async = false) { blockingDelay("Sync") }
private val blockingAsync = route("/async-blocking", GET) { blockingDelay("Blocking Async") }
private val nonBlockingAsync = route("/async", GET) { nonBlockingDelay("Non-blocking Async") }
override val routes = setOf(sync, blockingAsync, nonBlockingAsync)
}
private suspend fun nonBlockingDelay(message: String): String = delay(100L).let { message }
@Suppress("BlockingMethodInNonBlockingContext")
private suspend fun blockingDelay(message: String): String = sleep(100L).let { message }
fun main() {
val exampleFacade = ExampleFacade()
val exampleEndpoint = ExampleEndpoint(exampleFacade)
val sharedThreadPool = QueuedThreadPool(4)
val dispatcher = DispatcherWithShutdown(sharedThreadPool.asCoroutineDispatcher())
sharedThreadPool.start()
Javalin
.create { config ->
config.server { Server(sharedThreadPool) }
ReactiveRoutingPlugin(
errorConsumer = { name, throwable -> println("$name: ${throwable.message}") },
dispatcher = dispatcher,
syncHandler = { ctx, route -> route.handler(AppContext(ctx)) },
asyncHandler = { ctx, route, _ -> route.handler(AppContext(ctx)) }
)
.registerRoutes(exampleEndpoint)
.let { config.registerPlugin(it) }
}
.events {
it.serverStopping { dispatcher.prepareShutdown() }
it.serverStopped { dispatcher.completeShutdown() }
}
.start("127.0.0.1", 8080)
}
“>
// Custom context class AppContext(val context: Context) // Some dependencies class ExampleFacade // Endpoint (domain router) class ExampleEndpoint(private val exampleFacade: ExampleFacade) : AbstractRoutes<AppContext, Unit>() { private val sync = route("/sync", GET, async = false) { blockingDelay("Sync") } private val blockingAsync = route("/async-blocking", GET) { blockingDelay("Blocking Async") } private val nonBlockingAsync = route("/async", GET) { nonBlockingDelay("Non-blocking Async") } override val routes = setOf(sync, blockingAsync, nonBlockingAsync) } private suspend fun nonBlockingDelay(message: String): String = delay(100L).let { message } @Suppress("BlockingMethodInNonBlockingContext") private suspend fun blockingDelay(message: String): String = sleep(100L).let { message } fun main() { val exampleFacade = ExampleFacade() val exampleEndpoint = ExampleEndpoint(exampleFacade) val sharedThreadPool = QueuedThreadPool(4) val dispatcher = DispatcherWithShutdown(sharedThreadPool.asCoroutineDispatcher()) sharedThreadPool.start() Javalin .create { config -> config.server { Server(sharedThreadPool) } ReactiveRoutingPlugin<AppContext, Unit>( errorConsumer = { name, throwable -> println("$name: ${throwable.message}") }, dispatcher = dispatcher, syncHandler = { ctx, route -> route.handler(AppContext(ctx)) }, asyncHandler = { ctx, route, _ -> route.handler(AppContext(ctx)) } ) .registerRoutes(exampleEndpoint) .let { config.registerPlugin(it) } } .events { it.serverStopping { dispatcher.prepareShutdown() } it.serverStopped { dispatcher.completeShutdown() } } .start("127.0.0.1", 8080) }