Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kotlin ConfigurationProperties default values are not picked up when nativeRun is used #34157

Closed
gzeskas opened this issue Feb 9, 2023 · 4 comments
Assignees
Labels
type: bug A general bug
Milestone

Comments

@gzeskas
Copy link

gzeskas commented Feb 9, 2023

spring-boot version: 3.0.2

gradle file from example application:

plugins {
	id("org.springframework.boot") version "3.0.2"
	id("io.spring.dependency-management") version "1.1.0"
	id("org.graalvm.buildtools.native") version "0.9.18"
	kotlin("jvm") version "1.7.22"
	kotlin("plugin.spring") version "1.7.22"
}

group = "com.example"
version = "0.0.1-SNAPSHOT"
java.sourceCompatibility = JavaVersion.VERSION_17

repositories {
	mavenCentral()
}

dependencies {
	implementation("org.springframework.boot:spring-boot-starter-webflux")
	implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
	implementation("io.projectreactor.kotlin:reactor-kotlin-extensions")
	implementation("org.jetbrains.kotlin:kotlin-reflect")
	implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
	implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor")
	testImplementation("org.springframework.boot:spring-boot-starter-test")
	testImplementation("io.projectreactor:reactor-test")
}

tasks.withType<KotlinCompile> {
	kotlinOptions {
		freeCompilerArgs = listOf("-Xjsr305=strict")
		jvmTarget = "17"
	}
}

tasks.withType<Test> {
	useJUnitPlatform()
}

Example application:

@SpringBootApplication
@EnableConfigurationProperties(
	AppProperties::class
)
class DemoApplication

fun main(args: Array<String>) {
	runApplication<DemoApplication>(*args)
}

@ConfigurationProperties("app.property")
data class AppProperties(
	var a: Boolean = true,
)


@RestController
@RequestMapping("/")
class TestController(val appProperty: AppProperties) {

	@GetMapping()
	fun hello(): String {
		return "Hello world: ${appProperty.a}"
	}

}

Exception that is thrown when command ./gradlew nativeRun is run:

Caused by: kotlin.reflect.jvm.internal.KotlinReflectionInternalError: This callable does not support a default call: public constructor AppProperties(a: kotlin.Boolean = ...) defined in com.example.demo.AppProperties[DeserializedClassConstructorDescriptor@7f41fb4b]
        at kotlin.reflect.jvm.internal.KCallableImpl.callDefaultMethod$kotlin_reflection(KCallableImpl.kt:164) ~[demo:1.7.22-release-288(1.7.22)]
        at kotlin.reflect.jvm.internal.KCallableImpl.callBy(KCallableImpl.kt:112) ~[demo:1.7.22-release-288(1.7.22)]
        at org.springframework.beans.BeanUtils$KotlinDelegate.instantiateClass(BeanUtils.java:895) ~[na:na]
        at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:191) ~[na:na]
        at org.springframework.boot.context.properties.bind.ValueObjectBinder$ValueObject.instantiate(ValueObjectBinder.java:178) ~[demo:3.0.2]
        at org.springframework.boot.context.properties.bind.ValueObjectBinder.create(ValueObjectBinder.java:97) ~[demo:3.0.2]
        at org.springframework.boot.context.properties.bind.Binder.create(Binder.java:369) ~[demo:3.0.2]
        at org.springframework.boot.context.properties.bind.Binder.handleBindResult(Binder.java:358) ~[demo:3.0.2]
        at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:344) ~[demo:3.0.2]
        at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:332) ~[demo:3.0.2]
        at org.springframework.boot.context.properties.bind.Binder.bindOrCreate(Binder.java:324) ~[demo:3.0.2]
        at org.springframework.boot.context.properties.bind.Binder.bindOrCreate(Binder.java:309) ~[demo:3.0.2]
        at org.springframework.boot.context.properties.ConfigurationPropertiesBinder.bindOrCreate(ConfigurationPropertiesBinder.java:100) ~[demo:na]
        at org.springframework.boot.context.properties.ConstructorBound.from(ConstructorBound.java:43) ~[na:na]
        at com.example.demo.AppProperties__BeanDefinitions.getAppPropertiesInstance(AppProperties__BeanDefinitions.java:24) ~[na:na]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainInstanceFromSupplier(AbstractAutowireCapableBeanFactory.java:1225) ~[demo:6.0.4]
        ... 33 common frames omitted

But it works us expected if command ./gradlew bootRun is run.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Feb 9, 2023
@gzeskas
Copy link
Author

gzeskas commented Feb 11, 2023

Found a possible work-around for this issue.
Need to replace data class with class
Example that works:

@ConfigurationProperties("app.property")
class AppProperties {
	var a: Boolean = true
}

@wilkinsona
Copy link
Member

Thanks for the reproducer.

Compilation of the AppProperties data class with a default value produces bytecode with two constructors:

public com.example.gh34157.AppProperties(boolean);
public com.example.gh34157.AppProperties(boolean, int, kotlin.jvm.internal.DefaultConstructorMarker);

The reflection config that's generated at build time only permits access to one of these constructors:

  {
    "name": "com.example.gh34157.AppProperties",
    "queryAllDeclaredMethods": true,
    "methods": [
      {
        "name": "<init>",
        "parameterTypes": [
          "boolean"
        ]
      }
    ]
  },

In the case of a Kotlin data class, BindableRuntimeHintsRegistrar needs to allow the AppProperties(boolean, int, kotlin.jvm.internal.DefaultConstructorMarker) constructor to be called as well.

@sdeleuze Does Kotlin Reflect allow the constructors that are associated with AppProperties(boolean) to be identified, or should we just allow invocation of all declared constructors in the case of a Kotlin data class?

@wilkinsona wilkinsona added type: bug A general bug and removed status: waiting-for-triage An issue we've not yet triaged labels Feb 13, 2023
@wilkinsona wilkinsona added this to the 3.0.x milestone Feb 13, 2023
@wilkinsona wilkinsona added the status: waiting-for-internal-feedback An issue that needs input from a member or another Spring Team label Feb 13, 2023
@sdeleuze
Copy link
Contributor

I think you should allow the invocation of all declared constructors for Kotlin data classes.

@wilkinsona wilkinsona removed the status: waiting-for-internal-feedback An issue that needs input from a member or another Spring Team label Feb 13, 2023
@wilkinsona
Copy link
Member

Thank you, @sdeleuze.

@wilkinsona wilkinsona self-assigned this Feb 13, 2023
@wilkinsona wilkinsona modified the milestones: 3.0.x, 3.0.3 Feb 13, 2023
@wilkinsona wilkinsona changed the title kotlin ConfigurationProperties default values are not picked up when nativeRun is used Kotlin ConfigurationProperties default values are not picked up when nativeRun is used Feb 23, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug A general bug
Projects
None yet
Development

No branches or pull requests

4 participants