Bootique Kotlin Module


1. Overview

bootique-kotlin contains following modules:

  1. Kotlin APIs and extensions for Bootique;

  2. Kotlin Script Configuration Module;

  3. Configuration and Extensions for Bootique Modules;

  4. JacksonService which provides ObjectMapper with enabled KotlinModule.

2. TL;DR;

  • Use KotlinBootique instead of Bootique;

  • Use KotlinModule instead of Module, you can use KotlinModule with ConfigModule (just inherit both);

  • Use KotlinBQModuleProvider instead of BQModuleProvider;

  • Use extensions defined in Extensions.kt;

  • Use bootique-kotlin-configuration module to benefit from configuration written in Kotlin.

  • Use bootique-kotlin-jackson to get ObjectMapper with KotlinModule.

3. Getting started

Kotlin 1.3.10 used in project.

Latest stable version: Maven Central

Add dependency on needed parts in your build.gradle, or pom.xml:

// Kotlin Extensions for Bootique
compile("io.bootique.kotlin:bootique-kotlin:1.0.RC1")

// Kotlin Configuration Module
compile("io.bootique.kotlin:bootique-kotlin-config:1.0.RC1")

// Kotlin Configuration Module
compile("io.bootique.kotlin:bootique-kotlin-jackson:1.0.RC1")

// Kotlin Configuration and Extensions for Jetty. Also this adds dependency to bootique-jetty module.
compile("io.bootique.kotlin:bootique-kotlin-jetty:1.0.RC1")

// Kotlin Configuration and Extensions for Logback. Also this adds dependency to bootique-logback module.
compile("io.bootique.kotlin:bootique-kotlin-logback:1.0.RC1")

// Kotlin Configuration and Extensions for $moduleName$. Also this adds dependency to bootique-$moduleName$ module.
compile("io.bootique.kotlin:bootique-kotlin-$moduleName$:1.0.RC1")
Important

bootique-kotlin modules doesn’t include kotlin-stdlib-jdk8, or any other core kotlin libraries, since you can use newer kotlin version and usually you already have kotlin-stdlib-jdk8 in runtime. So there are list of additional dependencies for different bootique-kotlin modules:

bootique-kotlin-config:
  org.jetbrains.kotlin:kotlin-reflect
  org.jetbrains.kotlin:kotlin-script-util
  org.jetbrains.kotlin:kotlin-compiler-embeddable

bootique-kotlin-jackson:
  org.jetbrains.kotlin:kotlin-reflect

bootique-kotlin-logback:
  org.jetbrains.kotlin:kotlin-reflect

If you use different kotlin version, it’s much simpler to include this libraries with proper version, instead of excluding library version of them and then including again.

If you’d like to use snapshot versions, you have to add bootique snapshot repository:

http://maven.objectstyle.org/nexus/content/repositories/bootique-snapshots/

For example in gradle it can be done this way:

repositories {
    maven { setUrl("http://maven.objectstyle.org/nexus/content/repositories/bootique-snapshots/") }
}

And then use snapshot version: 1.0.RC2-SNAPSHOT.

4. Bootique

4.1. KotlinBootique

bootique-kotlin provides replacement for Bootique class - KotlinBootique:

fun main(args: Array<String>) {
    KotlinBootique(args)
        .module(ApplicationModule::class)
        .exec()
        .exit()
}

So no need for extensions for Bootique class, KotlinBootique provides best experience for developing Bootique apps with Kotlin.

4.2. KotlinBQModuleProvider

KotlinBQModuleProvider - interface to implement in Bootique Kotlin application instead of BQModuleProvider.

class ApplicationModuleProvider : KotlinBQModuleProvider {
    override val module = ApplicationModule()
    override val overrides = listOf(BQCoreModule::class)
    override val dependencies = listOf(KotlinConfigModule::class)
}

You can see how declarative become module provider.

4.3. Extension: ConfigurationFactory.config

// Using Java Api
configurationFactory.config(SampleFactory::class.java, "sample")

// With Extension
configurationFactory.config(SampleFactory::class, "sample")

// With Extension, reified generics
configurationFactory.config<SampleFactory>("sample")

// Type Inference
@Singleton
@Provides
fun createAppConfiguration(configurationFactory: ConfigurationFactory): SampleFactory {
    return configurationFactory.config/* No Type Here */(configPrefix)
}

4.4. Extension: BQCoreModuleExtender.addCommand

Straightforward and easy to use extension for contributing commands.

BQCoreModule
    .extend(binder)
    .addCommand(ApplicationCommand::class)

4.5. Extension: BQCoreModuleExtender.setDefaultCommand

Also extension for setDefaultCommand available.

BQCoreModule
    .extend(binder)
    .setDefaultCommand(ApplicationCommand::class)

4.6. Extensions

See Extensions.kt for sources.

4.7. Deprecated Extensions

These extensions deprecated and deleted in 0.25 in favor of KotlinModule and KotlinBootique.

  • LinkedBindingBuilder.toClass

  • ScopedBindingBuilder.asSingleton

  • ScopedBindingBuilder.inScope

  • Binder.bind

  • Bootique.module

  • Bootique.modules

4.8. Guice

4.8.1. KotlinModule

bootique-kotlin introduces new module interface to use with kotlin: KotlinModule

class ApplicationModule : KotlinModule {
    override fun configure(binder: KotlinBinder) {
        binder.bind(ShareCountService::class).to(DefaultShareCountService::class).asSingleton()
        binder.bind(HttpClient::class).to(DefaultHttpClient::class).asSingleton()
    }
}

4.8.2. Extensions

There are few function to help work with TypeLiteral and Key.

// TypeLiteral
typeLiteral<Array<String>>()

// Key
key<List<Callable<A>>>()

5. Configuration Module

Use Kotlin Script for configuration really simple:

  1. Create script

  2. Override ConfigurationFactory

5.1. Configuration with Kotlin can be defined in Kotlin Script file:

import io.bootique.kotlin.config.modules.config
import io.bootique.kotlin.config.modules.httpConnector
import io.bootique.kotlin.config.modules.jetty

config {
    jetty {
        httpConnector {
            port = 4242
            host = "0.0.0.0"
        }
    }
}

5.2. Enable Kotlin Script Configuration in Bootique:

With extension:

fun main(args: Array<String>) {
    KotlinBootique(args)
        .withKotlinConfig() // Extension function
        .autoLoadModules()
        .exec()
        .exit()
}

Using BQModuleProvider:

fun main(args: Array<String>) {
    KotlinBootique(args)
        .module(KotlinConfigModuleProvider())
        .autoLoadModules()
        .exec()
        .exit()
}

You can pass this file as always to bootique:

./bin/application --config=classpath:config.kts --server

It’s even support multiple files (each file contains map of configs):

./bin/application --config=classpath:config.kts --config=classpath:config1.kts --server

That’s it! You get autocomplete in IDE, and code for configuration!

6. Bootique Jetty

Define empty config:

config {
    jetty {

    }
}

Use autocompletion to define configuration.

Use httpConnector/httpsConnector extensions to define connectors:

jetty {
    httpConnector {
        port = 4242
        host = "192.168.0.1"
        responseHeaderSize = 42
        requestHeaderSize = 13
    }
}

7. Bootique Logback

Define logback configuration:

config {
    addConfig("log" to logbackContextFactory(
        logFormat = "[%d{dd/MMM/yyyy:HH:mm:ss}] %t %-5p %c{1}: %m%n",
        useLogbackConfig = false,
        debugLogback = false,
        level = LogbackLevel.warn,
        loggers = mapOf(
            logger(LogbackModuleTest::class, LogbackLevel.error),
            logger("TestLogger", LogbackLevel.trace)
        ),
        appenders = listOf(
            consoleAppender(
                logFormat = "[%d{dd/MMM/yyyy:HH:mm:ss}] %t %-5p %c{1}: %m%n",
                target = ConsoleTarget.stderr
            ),
            fileAppender(logFormat, "abc", timeBasedPolicy(
                fileNamePattern = "Abc_%d",
                totalSize = "2m",
                historySize = 1
            ))
        )
    ))
}

Use function for retrieving logger for class:

val logger = logger<SomeService>()

Or if class is generic:

val logger = logger<SomeService<*>>()

8. Bootique Undertow

Define undertow configuration:

config {
    addConfig("undertow" to undertowFactory(
        httpListeners = listOf(
            httpListener(1337, "127.0.0.1")
        ),
        workerThreads = 42
    ))
}