Bug Report for Spring Boot 3 Native (GraalVM 22.3) Having a simple Spring Boot application (generated on start.spring.io), changing the main class to:
@SpringBootApplication(proxyBeanMethods = false)
class DemoApplication {
companion object {
@JvmStatic
fun main(args: Array<String>) {
runApplication<DemoApplication>(*args)
}
}
}
And building the native image (via ./gradlew nativeCompile) gives you an executable that fails to start with:
2022-10-29T11:11:27.459+02:00 ERROR 8553 --- [ main] o.s.boot.SpringApplication : Application run failed
java.lang.IllegalArgumentException: Could not find class [com.example.demo.DemoApplication$Companion__ApplicationContextInitializer]
at org.springframework.util.ClassUtils.resolveClassName(ClassUtils.java:333) ~[na:na]
at org.springframework.context.aot.AotApplicationContextInitializer.instantiateInitializer(AotApplicationContextInitializer.java:80) ~[demo:6.0.0-RC2]
at org.springframework.context.aot.AotApplicationContextInitializer.initialize(AotApplicationContextInitializer.java:71) ~[demo:6.0.0-RC2]
at org.springframework.context.aot.AotApplicationContextInitializer.lambda$forInitializerClasses$0(AotApplicationContextInitializer.java:61) ~[demo:6.0.0-RC2]
at org.springframework.boot.SpringApplication.applyInitializers(SpringApplication.java:603) ~[demo:3.0.0-RC1]
at org.springframework.boot.SpringApplication.prepareContext(SpringApplication.java:383) ~[demo:3.0.0-RC1]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:307) ~[demo:3.0.0-RC1]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1302) ~[demo:3.0.0-RC1]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1291) ~[demo:3.0.0-RC1]
at com.example.demo.DemoApplication$Companion.main(DemoApplication.kt:15) ~[na:na]
at com.example.demo.DemoApplication.main(DemoApplication.kt) ~[demo:na]
Caused by: java.lang.ClassNotFoundException: com.example.demo.DemoApplication$Companion__ApplicationContextInitializer
at java.base@19.0.1/java.lang.Class.forName(DynamicHub.java:1132) ~[demo:na]
at org.springframework.util.ClassUtils.forName(ClassUtils.java:283) ~[na:na]
at org.springframework.util.ClassUtils.resolveClassName(ClassUtils.java:323) ~[na:na]
... 10 common frames omitted
Let me know if you need more information. Thanks.
Comment From: mhalbritter
Looks like we deduce the wrong class name for the application context initializer: com.example.demo.DemoApplication$Companion__ApplicationContextInitializer because of the Kotlin Companion Object. The generated initializer is called DemoApplication__ApplicationContextInitializer.
Workaround until fixed:
@SpringBootApplication
class DemoApplication
fun main(args: Array<String>) {
runApplication<DemoApplication>(*args)
}
which is the default code the initializer generates.
Comment From: akefirad
You're right. The workaround doesn't work for me since I have to set the main class in bootRun task in build.gradle, unless there's a way to set the main class in the task when the main method is a free one.
Comment From: mhalbritter
There is. The default class name for free functions is the filename + "Kt", so in your case DemoApplicationKt:
springBoot {
mainClass.set("com.example.demo.DemoApplicationKt")
}
You can rename the class by using
@file:JvmName("SomeOtherClassName")
springBoot {
mainClass.set("com.example.demo.SomeOtherClassName")
}
See here: https://kotlinlang.org/docs/java-to-kotlin-interop.html#package-level-functions
Comment From: akefirad
Got it. Thanks for the link. 🙏
Comment From: wilkinsona
The workaround doesn't work for me since I have to set the main class in
bootRuntask
This shouldn't be necessary. bootRun should be automatically configured to use the right main class when using either a companion object or a package-level function.
Comment From: wilkinsona
I wonder if we should set the main class in the Kotlin extension. Things are a little odd at the moment, even without AOT, as the companion object's class is used for logging:
2022-11-03T19:46:16.594Z INFO 33846 --- [ main] e.k.KotlinMainClassApplication$Companion : Starting KotlinMainClassApplication.Companion using Java 17.0.5 with PID 33846 (/Users/awilkinson/dev/temp/kotlin-main-class/build/classes/kotlin/main started by awilkinson in /Users/awilkinson/dev/temp/kotlin-main-class)
If we set the main class, it looks like this instead:
2022-11-03T19:48:04.743Z INFO 35059 --- [ main] c.e.k.KotlinMainClassApplication : Starting KotlinMainClassApplication using Java 17.0.5 with PID 35059 (/Users/awilkinson/dev/temp/kotlin-main-class/build/classes/kotlin/main started by awilkinson in /Users/awilkinson/dev/temp/kotlin-main-class)
That's after making these changes to the extensions:
diff --git a/spring-boot-project/spring-boot/src/main/kotlin/org/springframework/boot/SpringApplicationExtensions.kt b/spring-boot-project/spring-boot/src/main/kotlin/org/springframework/boot/SpringApplicationExtensions.kt
index 8a1269d06b..3ae3cdbc6c 100644
--- a/spring-boot-project/spring-boot/src/main/kotlin/org/springframework/boot/SpringApplicationExtensions.kt
+++ b/spring-boot-project/spring-boot/src/main/kotlin/org/springframework/boot/SpringApplicationExtensions.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2017 the original author or authors.
+ * Copyright 2012-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,8 +26,12 @@ import org.springframework.context.ConfigurableApplicationContext
* @author Sebastien Deleuze
* @since 2.0.0
*/
-inline fun <reified T : Any> runApplication(vararg args: String): ConfigurableApplicationContext =
- SpringApplication.run(T::class.java, *args)
+inline fun <reified T : Any> runApplication(vararg args: String): ConfigurableApplicationContext {
+ val application = SpringApplication(T::class.java)
+ application.setMainApplicationClass(T::class.java)
+ return application.run(*args)
+}
+
/**
* Top level function acting as a Kotlin shortcut allowing to write
@@ -38,5 +42,8 @@ inline fun <reified T : Any> runApplication(vararg args: String): ConfigurableAp
* @author Sebastien Deleuze
* @since 2.0.0
*/
-inline fun <reified T : Any> runApplication(vararg args: String, init: SpringApplication.() -> Unit): ConfigurableApplicationContext =
- SpringApplication(T::class.java).apply(init).run(*args)
+inline fun <reified T : Any> runApplication(vararg args: String, init: SpringApplication.() -> Unit): ConfigurableApplicationContext {
+ val application = SpringApplication(T::class.java).apply(init)
+ application.setMainApplicationClass(T::class.java)
+ return application.run(*args)
+}
WDYT, @sdeleuze, does this make sense?
Comment From: wilkinsona
Looking more closely, I think this is a bug in the code where we deduce the main application class. It can effect Java too if you write some (convoluted) code that has a similar structure to the code the Kotlin's compiler generates:
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
Companion.main(args);
}
static class Companion {
static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
}
SpringApplicaton will deduce the main class to be DemoApplication$Companion but the MainClassFinder that's used by our Maven and Gradle plugins will correctly identify that it's DemoApplication.
At the moment we identify the main class by walking the stack and finding the first frame for a method named main. In the example above, we really need to look for the last frame. However, by doing that we risk picking up another main method that's then called the application's main method to start it. @SpringBootTests configured to use the main method would be affected by this were it not for the fact that they explicitly set the main application class.
We can't narrow things down by looking for a particular type of method as it doesn't work with Graal. For the reasons above, I'm also not sure that we can safely look for the last method named main rather than the first. I'm back to thinking that a Kotlin-specific fix may be our best option.
Comment From: wilkinsona
Here's a change that corrects the main class only when a companion object is used:
diff --git a/spring-boot-project/spring-boot/src/main/kotlin/org/springframework/boot/SpringApplicationExtensions.kt b/spring-boot-project/spring-boot/src/main/kotlin/org/springframework/boot/SpringApplicationExtensions.kt
index 8a1269d06b..2405a00f2e 100644
--- a/spring-boot-project/spring-boot/src/main/kotlin/org/springframework/boot/SpringApplicationExtensions.kt
+++ b/spring-boot-project/spring-boot/src/main/kotlin/org/springframework/boot/SpringApplicationExtensions.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2017 the original author or authors.
+ * Copyright 2012-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,8 +26,15 @@ import org.springframework.context.ConfigurableApplicationContext
* @author Sebastien Deleuze
* @since 2.0.0
*/
-inline fun <reified T : Any> runApplication(vararg args: String): ConfigurableApplicationContext =
- SpringApplication.run(T::class.java, *args)
+inline fun <reified T : Any> runApplication(vararg args: String): ConfigurableApplicationContext {
+ val application = SpringApplication(T::class.java)
+ val possibleCompanionClass = object{}.javaClass.enclosingClass
+ if (possibleCompanionClass.enclosingClass != null && possibleCompanionClass.kotlin.isCompanion) {
+ application.setMainApplicationClass(possibleCompanionClass.enclosingClass)
+ }
+ return application.run(*args)
+}
+
/**
* Top level function acting as a Kotlin shortcut allowing to write
@@ -38,5 +45,11 @@ inline fun <reified T : Any> runApplication(vararg args: String): ConfigurableAp
* @author Sebastien Deleuze
* @since 2.0.0
*/
-inline fun <reified T : Any> runApplication(vararg args: String, init: SpringApplication.() -> Unit): ConfigurableApplicationContext =
- SpringApplication(T::class.java).apply(init).run(*args)
+inline fun <reified T : Any> runApplication(vararg args: String, init: SpringApplication.() -> Unit): ConfigurableApplicationContext {
+ val application = SpringApplication(T::class.java).apply(init)
+ val possibleCompanionClass = object{}.javaClass.enclosingClass
+ if (possibleCompanionClass.enclosingClass != null && possibleCompanionClass.kotlin.isCompanion) {
+ application.setMainApplicationClass(possibleCompanionClass.enclosingClass)
+ }
+ return application.run(*args)
+}
It's pretty gross. It's using an anonymous inner class (object{}) and then getting the enclosing class to identify the class into which the function has been inlined. We can then check if it's a companion class and set the main application class if it is.
Comment From: alsikorski
I had the same problem in Java and found a workaround. Maybe that'll help you somehow.
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
Companion.main(args);
}
static class Companion {
static void main(String[] args) {
SpringApplication springApplication = new SpringApplication(DemoApplication.class);
springApplication.setMainApplicationClass(DemoApplication.class);
springApplication.run(args);
}
}
}
Comment From: takanoro
Have the same problem. No luck with workarounds that were mentioned here.
java.lang.IllegalArgumentException: Could not find class [xyz.app.ApplicationKt__ApplicationContextInitializer]
at org.springframework.util.ClassUtils.resolveClassName(ClassUtils.java:333)
at org.springframework.context.aot.AotApplicationContextInitializer.instantiateInitializer(AotApplicationContextInitializer.java:80)
at org.springframework.context.aot.AotApplicationContextInitializer.initialize(AotApplicationContextInitializer.java:71)
at org.springframework.context.aot.AotApplicationContextInitializer.lambda$forInitializerClasses$0(AotApplicationContextInitializer.java:61)
at org.springframework.boot.SpringApplication.applyInitializers(SpringApplication.java:605)
at org.springframework.boot.SpringApplication.prepareContext(SpringApplication.java:385)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:309)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1304)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1293)
at xyz.app.ApplicationKt.main(Application.kt:13)
Caused by: java.lang.ClassNotFoundException: xyz.app.ApplicationKt__ApplicationContextInitializer
at java.base@17.0.6/java.lang.Class.forName(DynamicHub.java:1132)
at org.springframework.util.ClassUtils.forName(ClassUtils.java:283)
at org.springframework.util.ClassUtils.resolveClassName(ClassUtils.java:323)
build.gradle.kts
plugins {
id("org.springframework.boot") version "3.0.5"
id("io.spring.dependency-management") version "1.0.13.RELEASE"
kotlin("jvm") version "1.8.10"
kotlin("plugin.spring") version "1.8.10"
kotlin("kapt") version "1.8.10"
}
...
tasks.bootBuildImage {
builder.set("paketobuildpacks/builder:tiny")
environment.set(
mapOf(
"BP_NATIVE_IMAGE" to "true",
"BP_NATIVE_IMAGE_BUILD_ARGUMENTS" to
"""
--verbose
--no-fallback
--initialize-at-build-time=org.slf4j.LoggerFactory,ch.qos.logback
--trace-class-initialization=ch.qos.logback.classic.Logger
--initialize-at-run-time=io.netty
""".trimIndent()
)
)
}
Comment From: FloHin
We can confirm @takanoro's problem, even tried the approach to rename the kotlin main class accordingly
DemoMain.kt
@file:JvmName("DemoMain")
package at.demo
import org.springframework.boot.runApplication
fun main(args: Array<String>) {
runApplication<DemoApp>(*args)
}
DemoApp.kt
@EnableScheduling
@SpringBootApplication(
...
)
@ConfigurationPropertiesScan
...
class DemoApp
build.gradle:
plugins {
id 'org.springframework.boot' version '3.1.0'
id 'io.spring.dependency-management'
id 'org.asciidoctor.jvm.convert' version "2.4.0"
id 'org.graalvm.buildtools.native' version '0.9.22'
}
....
springBoot {
mainClass = 'at.demo.DemoMain'
}
....
bootBuildImage {
enabled = true
builder = "paketobuildpacks/builder:tiny"
imageName = "ghcr.io/demo/demo:native"
environment = [
"BP_NATIVE_IMAGE" : "true",
"BP_NATIVE_IMAGE_BUILD_ARGUMENTS": "" +
"--verbose " +
"--no-fallback " +
"--enable-https " +
"-Djdk.tls.client.protocols=TLSv1.2 " +
"--add-opens=java.base/java.time=ALL-UNNAMED " +
"--add-opens=java.base/java.nio=ALL-UNNAMED " +
"--add-opens=java.base/jdk.internal.misc=ALL-UNNAMED " +
"--add-opens=java.base/jdk.internal.ref=ALL-UNNAMED " +
"--trace-class-initialization=ch.qos.logback.classic.Logger " +
'--trace-object-instantiation=ch.qos.logback.core.AsyncAppenderBase$Worker ' +
"--initialize-at-build-time=org.slf4j.LoggerFactory,ch.qos.logback " +
"--initialize-at-run-time=io.netty " +
"--report-unsupported-elements-at-runtime "
]
}
I tried both with 3.0 and 3.1 spring versions. Which finally results in a built image which cannot start its main class:
2023-06-09T12:19:17.190254236Z . ____ _ __ _ _
2023-06-09T12:19:17.190256831Z /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
2023-06-09T12:19:17.190258664Z ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
2023-06-09T12:19:17.190260327Z \\/ ___)| |_)| | | | | || (_| | ) ) ) )
2023-06-09T12:19:17.190261900Z ' |____| .__|_| |_|_| |_\__, | / / / /
2023-06-09T12:19:17.190263794Z =========|_|==============|___/=/_/_/_/
2023-06-09T12:19:17.190265387Z :: Spring Boot :: (v3.1.0)
2023-06-09T12:19:17.190267571Z
2023-06-09T12:19:17.191701237Z 12:19:17.190 [main] ERROR org.springframework.boot.SpringApplication -- Application run failed
2023-06-09T12:19:17.191726434Z java.lang.IllegalArgumentException: Could not find class [at.demo.DemoMain__ApplicationContextInitializer]
2023-06-09T12:19:17.191730531Z at org.springframework.util.ClassUtils.resolveClassName(ClassUtils.java:334)
2023-06-09T12:19:17.191734148Z at org.springframework.context.aot.AotApplicationContextInitializer.instantiateInitializer(AotApplicationContextInitializer.java:80)
2023-06-09T12:19:17.191737675Z at org.springframework.context.aot.AotApplicationContextInitializer.initialize(AotApplicationContextInitializer.java:71)
2023-06-09T12:19:17.191741051Z at org.springframework.context.aot.AotApplicationContextInitializer.lambda$forInitializerClasses$0(AotApplicationContextInitializer.java:61)
2023-06-09T12:19:17.191744327Z at org.springframework.boot.SpringApplication.applyInitializers(SpringApplication.java:606)
2023-06-09T12:19:17.191747433Z at org.springframework.boot.SpringApplication.prepareContext(SpringApplication.java:386)
2023-06-09T12:19:17.191764495Z at org.springframework.boot.SpringApplication.run(SpringApplication.java:310)
2023-06-09T12:19:17.191770025Z at org.springframework.boot.SpringApplication.run(SpringApplication.java:1305)
2023-06-09T12:19:17.191775255Z at org.springframework.boot.SpringApplication.run(SpringApplication.java:1294)
2023-06-09T12:19:17.191779933Z at at.demo.DemoMain.main(DemoMain.kt:11)
2023-06-09T12:19:17.191784502Z Caused by: java.lang.ClassNotFoundException: at.demo.DemoMain__ApplicationContextInitializer
2023-06-09T12:19:17.191788910Z at java.base@17.0.7/java.lang.Class.forName(DynamicHub.java:1132)
2023-06-09T12:19:17.191793268Z at org.springframework.util.ClassUtils.forName(ClassUtils.java:284)
2023-06-09T12:19:17.191797226Z at org.springframework.util.ClassUtils.resolveClassName(ClassUtils.java:324)
2023-06-09T12:19:17.191800812Z ... 9 common frames omitted
Comment From: changhr2013
so is there any temporary solution to this problem?
Comment From: mhalbritter
@SpringBootApplication
class Sb32918Application
fun main(args: Array<String>) {
runApplication<Sb32918Application>(*args)
}
works for me, try for yourself: sb-32918.zip
Could you please attach a sample for a non-working app?
Comment From: changhr2013
@mhalbritter my mistake, it missed mainClass because of I configured the native-maven-plugin incorrectly, thanks for your help.
Comment From: Eng-Fouad
This happened when upgrading to spring-boot 3.2.0-M1.
Comment From: mbogner
I think I'm facing the same issue with Spring 3.1.2.
The application compiles but when I run it I get an error.
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v3.1.2)
02:12:34.177 [main] ERROR org.springframework.boot.SpringApplication -- Application run failed
java.lang.IllegalArgumentException: Could not find class [dev.mbo.linkshortener2.ApplicationKt__ApplicationContextInitializer]
at org.springframework.util.ClassUtils.resolveClassName(ClassUtils.java:334)
at org.springframework.context.aot.AotApplicationContextInitializer.instantiateInitializer(AotApplicationContextInitializer.java:80)
at org.springframework.context.aot.AotApplicationContextInitializer.initialize(AotApplicationContextInitializer.java:71)
at org.springframework.context.aot.AotApplicationContextInitializer.lambda$forInitializerClasses$0(AotApplicationContextInitializer.java:61)
at org.springframework.boot.SpringApplication.applyInitializers(SpringApplication.java:607)
at org.springframework.boot.SpringApplication.prepareContext(SpringApplication.java:387)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:311)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295)
at dev.mbo.linkshortener2.ApplicationKt.main(Application.kt:29)
Caused by: java.lang.ClassNotFoundException: dev.mbo.linkshortener2.ApplicationKt__ApplicationContextInitializer
at org.graalvm.nativeimage.builder/com.oracle.svm.core.hub.ClassForNameSupport.forName(ClassForNameSupport.java:123)
at org.graalvm.nativeimage.builder/com.oracle.svm.core.hub.ClassForNameSupport.forName(ClassForNameSupport.java:87)
at java.base@17.0.8/java.lang.Class.forName(DynamicHub.java:1322)
at java.base@17.0.8/java.lang.Class.forName(DynamicHub.java:1311)
at org.springframework.util.ClassUtils.forName(ClassUtils.java:284)
at org.springframework.util.ClassUtils.resolveClassName(ClassUtils.java:324)
... 9 common frames omitted
My build.gradle.kts:
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
// https://plugins.gradle.org/plugin/org.springframework.boot
id("org.springframework.boot") version "3.1.2"
// https://plugins.gradle.org/plugin/io.spring.dependency-management
id("io.spring.dependency-management") version "1.1.3"
// https://github.com/graalvm/native-build-tools
id("org.graalvm.buildtools.native") version "0.9.24"
// https://plugins.gradle.org/plugin/org.jetbrains.kotlin.jvm
kotlin("jvm") version "1.9.0"
// https://plugins.gradle.org/plugin/org.jetbrains.kotlin.plugin.spring
kotlin("plugin.spring") version "1.9.0"
}
group = "dev.mbo"
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(17))
}
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-actuator")
implementation("org.springframework.boot:spring-boot-starter-data-redis-reactive")
implementation("org.springframework.boot:spring-boot-starter-mail")
implementation("org.springframework.boot:spring-boot-starter-security")
implementation("org.springframework.boot:spring-boot-starter-validation")
implementation("org.springframework.boot:spring-boot-starter-webflux")
implementation("org.springframework.boot:spring-boot-starter-thymeleaf")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310")
implementation("io.projectreactor.kotlin:reactor-kotlin-extensions")
// https://mvnrepository.com/artifact/io.netty/netty-resolver-dns-native-macos
implementation("io.netty:netty-resolver-dns-native-macos:4.1.96.Final:osx-aarch_64")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor")
developmentOnly("org.springframework.boot:spring-boot-devtools")
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("org.springframework.boot:spring-boot-testcontainers")
testImplementation("io.projectreactor:reactor-test")
testImplementation("org.springframework.security:spring-security-test")
testImplementation("org.testcontainers:junit-jupiter")
}
tasks {
withType<KotlinCompile> {
kotlinOptions {
freeCompilerArgs += "-Xjsr305=strict"
jvmTarget = "17"
}
}
withType<Test> {
useJUnitPlatform()
}
withType<Copy> {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
bootJar {
archiveFileName = "${project.name}-all.jar"
exclude("application-sec*.yml")
}
withType<Wrapper> {
// https://gradle.org/releases/
gradleVersion = "8.2.1"
distributionType = Wrapper.DistributionType.ALL
}
graalvmNative {
binaries {
named("main") {
mainClass.set("dev.mbo.linkshortener2.ApplicationKt")
}
}
}
}
Without setting the main class like a few lines above the nativeCompile task fails.
My main looks like this:
package dev.mbo.linkshortener2
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
@SpringBootApplication
class Application
fun main(args: Array<String>) {
runApplication<Application>(*args)
}
Starting the application from the bootJar works fine. Setting mainClass.set("dev.mbo.linkshortener2.Application") complained about not finding the main method.
Comment From: mhalbritter
Can you share the code with us so I can take a look?
Comment From: rt-works
Having the same issue on Spring Boot 3.1.0, Kotlin , Gradle.
I don't use nativeImage plugin, I use buildpacks. I get with bootBuildImage a built docker image, which can't start with the same error:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v3.1.0)
15:49:31.620 [main] ERROR org.springframework.boot.SpringApplication -- Application run failed
java.lang.IllegalArgumentException: Could not find class [com.***.ManagementApplicationKt__ApplicationContextInitializer]
at org.springframework.util.ClassUtils.resolveClassName(ClassUtils.java:334)
at org.springframework.context.aot.AotApplicationContextInitializer.instantiateInitializer(AotApplicationContextInitializer.java:80)
at org.springframework.context.aot.AotApplicationContextInitializer.initialize(AotApplicationContextInitializer.java:71)
at org.springframework.context.aot.AotApplicationContextInitializer.lambda$forInitializerClasses$0(AotApplicationContextInitializer.java:61)
at org.springframework.boot.SpringApplication.applyInitializers(SpringApplication.java:606)
at org.springframework.boot.SpringApplication.prepareContext(SpringApplication.java:386)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:310)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1305)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1294)
at com.deliveryhero.vms.VendorManagementApplicationKt.main(VendorManagementApplication.kt:33)
Caused by: java.lang.ClassNotFoundException: com.***.ManagementApplicationKt__ApplicationContextInitializer
at com.oracle.svm.core.hub.ClassForNameSupport.forName(ClassForNameSupport.java:123)
at com.oracle.svm.core.hub.ClassForNameSupport.forName(ClassForNameSupport.java:87)
at java.base@17.0.7/java.lang.Class.forName(DynamicHub.java:1324)
at java.base@17.0.7/java.lang.Class.forName(DynamicHub.java:1313)
at org.springframework.util.ClassUtils.forName(ClassUtils.java:284)
at org.springframework.util.ClassUtils.resolveClassName(ClassUtils.java:324)
... 9 common frames omitted
my root class:
@SpringBootApplication
@EnableConfigurationProperties(
...
)
@EnableAsync
class ***ManagementApplication
fun main(args: Array<String>) {
runApplication<***ManagementApplication>(*args)
}
This is my gradle.build part related to the graalvm and native image
plugins {
kotlin("jvm")
kotlin("plugin.spring")
id("io.spring.dependency-management")
id("org.springframework.boot")
id("org.graalvm.buildtools.native") version "0.9.23"
id("com.avast.gradle.docker-compose")
id("com.adarshr.test-logger")
jacoco
}
tasks.named<BootBuildImage>("bootBuildImage") {
environment.set(
environment.get() + mapOf(
"BP_NATIVE_IMAGE" to "true",
"BP_NATIVE_IMAGE_BUILD_ARGUMENTS" to "--initialize-at-build-time=org.slf4j.impl.StaticLoggerBinder,org.slf4j.LoggerFactory,ch.qos.logback.classic.Logger,ch.qos.logback.core.spi.AppenderAttachableImpl,ch.qos.logback.core.status.StatusBase,ch.qos.logback.classic.Level,ch.qos.logback.core.status.InfoStatus,ch.qos.logback.classic.PatternLayout,ch.qos.logback.core.CoreConstants,ch.qos.logback.core.util.StatusPrinter,ch.qos.logback.core.util.Loader"
)
)
}
Comment From: mbogner
@mhalbritter uploaded to https://github.com/mbogner/link-shortener2
highly work in progress but it runs as jar on my mac M1. didn't work on the dockerisation scripts yet that are included
Comment From: rt-works
I compared my build with a hello-world project generated from start.spring.io. They bootBuildImage task generates this classes for the hello world project like
but it's not generated for my current project.
PS: I also use a multimodule gradle project and build like:
./gradlew -Pversion=v1 :management-service:bootBuildImage --runImage=paketobuildpacks/run:full-cnb
PPS: Somehow after
./gradlew -Pversion=v1 :management-service:bootBuildImage --runImage=paketobuildpacks/run:full-cnb
the folder build/generated with all AOT classes is missing for me
Comment From: kkocel
I tried various workarounds, none worked.
@file:JvmName("MyApp")
package com.example.my
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity
@SpringBootApplication
@EnableWebFluxSecurity
class MyApplication
fun main(args: Array<String>) {
runApplication<MyApplication>(*args)
}
application {
mainClass.set("com.example.my.MyApp")
}
When running :nativeRun:
Caused by: java.lang.ClassNotFoundException: com.example.my.MyApp__ApplicationContextInitializer
I tried with 3.1.2 and 3.1.0
EDIT: I gave another shot - I rewrote main in Java and it seems that the same error (ClassNotFoundException: com.example.my.MyApp__ApplicationContextInitializer) occurs. FYI @wilkinsona
Comment From: kkocel
I made a project that reproduces this issue - it has two branches: one with Kotlin main and another with Java main. Both fail with the same error. https://github.com/kkocel/classnotfoundrepero
Comment From: rt-works
@kkocel I played around with your main branch to understand why it happens and noticed that when I only downgrade to Kotlin 1.8.22 your example builds and run without the exception.
kotlin("jvm") version "1.8.22"
kotlin("plugin.spring") version "1.8.22"
docker run --rm -p 8080:8080 docker.io/library/classnotfoundrepero:0.0.1-SNAPSHOT
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v3.1.2)
2023-08-22T14:38:01.076Z INFO 1 --- [ main] c.e.c.ClassnotfoundreperoApplicationKt : Starting AOT-processed ClassnotfoundreperoApplicationKt using Java 17.0.7 with PID 1 (/workspace/com.example.classnotfoundrepero.ClassnotfoundreperoApplicationKt started by cnb in /workspace)
2023-08-22T14:38:01.076Z INFO 1 --- [ main] c.e.c.ClassnotfoundreperoApplicationKt : No active profile set, falling back to 1 default profile: "default"
2023-08-22T14:38:01.116Z INFO 1 --- [ main] o.s.b.a.e.web.EndpointLinksResolver : Exposing 1 endpoint(s) beneath base path '/actuator'
2023-08-22T14:38:01.136Z INFO 1 --- [ main] o.s.b.web.embedded.netty.NettyWebServer : Netty started on port 8080
2023-08-22T14:38:01.137Z INFO 1 --- [ main] c.e.c.ClassnotfoundreperoApplicationKt : Started ClassnotfoundreperoApplicationKt in 0.074 seconds (process running for 0.079)
Comment From: mhalbritter
Thanks for analyzing, @rt-works!
Comment From: kkocel
@mhalbritter So is there a chance that this issue will get resolved soon?
Comment From: rt-works
In my case my problem was just solved by upgrading to id("org.graalvm.buildtools.native") version "0.9.24". After the the application could start but there are a lot of other errors to solve in runtime.
Comment From: kkocel
@rt-works do you have a minimal working example? do yo use kotlin 1.9 + native buildtools 0.9.24?
Comment From: rt-works
it works for me with kotlin 1.8.22 + native buildtools 0.9.24. I'll prepare the example
Comment From: kkocel
sorry for the confusion. I thought you managed to run this against Kotlin 1.9.0.
So for now we pin-pointed that Kotlin 1.9.0 is causing this issue.
Comment From: artemptushkin
Any update for Kotlin 1.9.*?
Having a simple project, I have the same issue, I'm on:
- org.graalvm.buildtools.native: 0.9.27
- spring-boot 3.1.4
- gradle 8.4
- JDK 17 GraalVM
- Kotlin 1.9.10
# .kts
springBoot {
mainClass.set("com.iptiq.apptemplate.AppTemplateApplicationKt")
}
graalvmNative {
binaries {
named("main") {
mainClass = "foo.baz.apptemplate.AppTemplateApplicationKt"
buildArgs(
"-H:+ReportExceptionStackTraces",
"-H:EnableURLProtocols=http,https",
"--initialize-at-run-time=io.netty.handler.ssl.BouncyCastleAlpnSslUtils",
"--initialize-at-build-time=org.slf4j.impl.StaticLoggerBinder,org.slf4j.LoggerFactory,ch.qos.logback.core.spi.AppenderAttachableImpl,ch.qos.logback.core.status.StatusBase,ch.qos.logback.classic.Level,ch.qos.logback.core.status.InfoStatus,ch.qos.logback.classic.PatternLayout,ch.qos.logback.core.CoreConstants,ch.qos.logback.classic.Logger,ch.qos.logback.core.util.Loader,ch.qos.logback.core.util.StatusPrinter"
)
}
}
}
I do just nativeCompile task and run the binary on M1
same stuff but ./gradlew bootBuildImage -i -s - works, it starts in docker
Comment From: kkocel
I can confirm that this issue no longer occurs as of SB 3.2 + Kotlin 1.9.20.
Main:
package com.example.graalvmrepro
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
@SpringBootApplication
class GraalvmreproApplication
fun main(args: Array<String>) {
runApplication<GraalvmreproApplication>(*args)
}
gradle script:
application {
mainClass.set("com.example.graalvmrepro.GraalvmreproApplicationKt")
}
Comment From: wilkinsona
@kkocel thanks, but, as far as I can tell, the issue as originally reported still occurs with Spring Boot 3.2 and Kotlin 1.9.20. In fact, it's got slightly worse as the error message is no longer as helpful as it was:
> Task :nativeRun FAILED
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v3.2.0)
2023-12-04T12:25:16.225Z ERROR 83509 --- [ main] o.s.boot.SpringApplication : Application run failed
java.lang.IllegalStateException: You are starting the application with AOT mode enabled but AOT processing hasn't happened. Please build your application with enabled AOT processing first, or remove the system property 'spring.aot.enabled' to run the application in regular mode
at org.springframework.util.Assert.state(Assert.java:76) ~[na:na]
at org.springframework.boot.SpringApplication.addAotGeneratedInitializerIfNecessary(SpringApplication.java:440) ~[gh-32918:3.2.0]
at org.springframework.boot.SpringApplication.prepareContext(SpringApplication.java:396) ~[gh-32918:3.2.0]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:322) ~[gh-32918:3.2.0]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1342) ~[gh-32918:3.2.0]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1331) ~[gh-32918:3.2.0]
at com.example.gh32918.Gh32918Application$Companion.main(Gh32918Application.kt:15) ~[na:na]
at com.example.gh32918.Gh32918Application.main(Gh32918Application.kt) ~[gh-32918:na]
I think we should consider refining or reverting https://github.com/spring-projects/spring-boot/pull/38188, particularly while this issue is unresolved.