hoplite icon indicating copy to clipboard operation
hoplite copied to clipboard

Unable to load configuration for a data class containing a `kotlin.time.Duration?`

Open chrisalbright opened this issue 4 months ago • 2 comments

I've been using Kotlin 2.0.20, but I've tested with 1.6.21 and get the same error regardless. I've included a sample project illustrating the problem. Ironically, I created this project (hoplite-test.zip) in order to demonstrate the issue and I'm seeing the same behavior but the underlying cause is different.

The original project I'm working on is manifesting with a ClassCastException:

Exception in thread "main" com.sksamuel.hoplite.ConfigException: Error loading config because:

    Could not instantiate class Simple from args [kotlin.time.Duration]: Expected args are [class kotlin.time.Duration]. Underlying error was java.lang.ClassCastException: Cannot cast java.lang.Long to kotlin.time.Duration
	at com.sksamuel.hoplite.ConfigLoaderKt$returnOrThrow$1.invoke(ConfigLoader.kt:315)
	at com.sksamuel.hoplite.ConfigLoaderKt$returnOrThrow$1.invoke(ConfigLoader.kt:312)
	at com.sksamuel.hoplite.fp.ValidatedKt.getOrElse(Validated.kt:115)
	at com.sksamuel.hoplite.ConfigLoaderKt.returnOrThrow(ConfigLoader.kt:312)
	at com.sksamuel.hoplite.ConfigLoader.returnOrThrow(ConfigLoader.kt:273)
	at SimpleKt.main(Simple.kt:33)
	at SimpleKt.main(Simple.kt)

The code that creates this stacktrace is

import com.sksamuel.hoplite.ConfigLoaderBuilder
import com.sksamuel.hoplite.ExperimentalHoplite
import com.sksamuel.hoplite.addResourceSource
import kotlin.time.Duration

data class Simple(val duration: Duration?)

@OptIn(ExperimentalHoplite::class)
fun main() {
    val simple = ConfigLoaderBuilder
        .default()
        .withExplicitSealedTypes()
        .addResourceSource("/duration.yml").build()
        .loadConfigOrThrow<Simple>()

    println(simple)
}

With this configuration file

duration: 5 minutes

The (slightly modified) build configuration is

plugins {
    kotlin("jvm") version "2.0.20"
    `java-library`
    `maven-publish`
}

java {
    toolchain {
        languageVersion.set(JavaLanguageVersion.of(11))
    }
}

repositories {
    mavenCentral()
    mavenLocal()
}

dependencies {
    kotlin("stdlib")
    val hopliteVersion = "2.8.2"
    implementation("com.sksamuel.hoplite:hoplite-core:$hopliteVersion")
    implementation("com.sksamuel.hoplite:hoplite-toml:$hopliteVersion")
    implementation("com.sksamuel.hoplite:hoplite-yaml:$hopliteVersion")
}

The demonstration project included here is also failing, but with a different underlying error:

com.sksamuel.hoplite.ConfigException: Error loading config because:

    Could not instantiate class org.example.NotWorking$Simple from args [kotlin.time.Duration]: Expected args are [class kotlin.time.Duration]. Underlying error was java.lang.IllegalArgumentException: argument type mismatch
	at com.sksamuel.hoplite.ConfigLoaderKt$returnOrThrow$1.invoke(ConfigLoader.kt:315)
	at com.sksamuel.hoplite.ConfigLoaderKt$returnOrThrow$1.invoke(ConfigLoader.kt:312)
	at com.sksamuel.hoplite.fp.ValidatedKt.getOrElse(Validated.kt:115)
	at com.sksamuel.hoplite.ConfigLoaderKt.returnOrThrow(ConfigLoader.kt:312)
	at com.sksamuel.hoplite.ConfigLoader.returnOrThrow(ConfigLoader.kt:273)
	at org.example.DemoKt.main(Demo.kt:186)
	at org.example.DemoKt.main(Demo.kt)

I've been trying to get it to fail the same way, but no success - maybe you'll see some difference in the configuration that isn't standing out to me.

In both cases the error is coming from the DataClassDecoder class (/com/sksamuel/hoplite/decoder/DataClassDecoder.kt:126, /com/sksamuel/hoplite/decoder/DataClassDecoder.kt:140, /com/sksamuel/hoplite/decoder/DataClassDecoder.kt:144)

I have only encountered this problem with kotlin.time.Duration?. kotlin.time.Duration works without any problem.

chrisalbright avatar Oct 10 '24 01:10 chrisalbright