dave08
01/28/2019, 5:15 PMApplicationConfig
... it's really a bit verbose right now. Instead of:
val username = config.property("username").getString()
, it could be val username: String by config
!!!bdawg.io
01/28/2019, 5:46 PMbdawg.io
01/28/2019, 5:48 PMgetValue
operator requires the parameters getValue(thisRef: T, property: KProperty<*>): String
. Since you can’t qualify it with KProperty<String>
, you can only provide a single parameter signature (which will require you to skip the getList()
variant)dave08
01/28/2019, 5:48 PMtoInt()
on the getString()
and so forth...dave08
01/28/2019, 5:48 PMdave08
01/28/2019, 5:49 PMdave08
01/28/2019, 5:51 PMval config = config("path.to.values")
...bdawg.io
01/28/2019, 6:05 PMval favoriteNumbers: List<String> by config.list()
and have a wrapper for ApplicationConfig
that exposes a getList
variantbdawg.io
01/28/2019, 6:07 PM// Default to accessing a single String value
operator fun ApplicationConfig.getValue(thisRef: Any?, property: KProperty<*>): String = property(property.name).getString()
// Expose a secondary read property wrapper
fun ApplicationConfig.list() = ApplicationListConfig(this)
class ApplicationListConfig(private val config: ApplicationConfig) : ReadOnlyProperty<Any?, List<String>> {
override fun getValue(thisRef: Any?, property: KProperty<*>): List<String> = config.property(property.name).getList()
}
val config: ApplicationConfig = TODO()
object Foo {
val username: String by config
val favoriteNumbers: List<String> by config.list()
}
dave08
01/28/2019, 6:08 PMApplicationListConfig
could even be an inline class
...dave08
01/28/2019, 6:09 PMby config
to support strings or ints (I have quite a few ports to handle in one app...).bdawg.io
01/28/2019, 6:10 PMgetValue
operatordave08
01/28/2019, 6:10 PMoperator fun ApplicationConfig.getValue(thisRef: Any?, property: KProperty<*>): String =
property(property.name).getString()
dave08
01/28/2019, 6:12 PMbdawg.io
01/28/2019, 6:15 PMinline operator fun <reified T> ApplicationConfig.getValue(thisRef: Any?, property: KProperty<*>): T = property(property.name).run {
when (T::class) {
String::class -> getString() as T
Int::class -> getString().toInt() as T
else -> error("Cannot handle type ${T::class}")
}
}
bdawg.io
01/28/2019, 6:16 PMdave08
01/28/2019, 6:17 PMtoInt()
would do that at runtime.dave08
01/28/2019, 6:20 PMdave08
01/28/2019, 6:22 PMclass DbConfigs(private val configs: ApplicationConfig) {
val host: String by configs
val port: Int by configs
// ...
}
dave08
01/28/2019, 6:23 PMbdawg.io
01/28/2019, 6:27 PMinline operator fun <reified T> ApplicationConfig.getValue(thisRef: Any?, property: KProperty<*>): T = property(property.name).run {
when (typeFor<T>()) {
String::class -> getString() as T
Int::class -> getString().toInt() as T
typeFor<List<String>>() -> getList() as T
typeFor<List<Int>>() -> getList().map { it.toInt() } as T
else -> error("Cannot handle type ${T::class}")
}
}
open class TypeEval<T> {
val argument get() = this::class.allSupertypes.first { it.jvmErasure == TypeEval::class }.arguments[0]
}
inline fun <reified T> typeFor() = (object : TypeEval<T>() {}).argument
dave08
01/28/2019, 6:30 PM