Hi, I use Spring Boot 3.1.5 with GraalVM 17.0.9 with spring-boot-maven-plugin and native-maven-plugin plugins. The following application fails during start bulding with native profile:

package com.example.boot;

import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class BootApplication {

    public static void main(String[] args) {
        WrapperApplication .main(args);
    }

}
public class WrapperApplication {
    public static void main(String[] args) {
        System.out.println("in wrapper app");
        SpringApplication.run(BootApplication.class);
    }
}

with the following exception

in wrapper app

  .   ____          _            __ _ _ 
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v3.1.5)

2023-11-07T10:52:57.826-05:00 ERROR 11260 --- [           main] o.s.boot.SpringApplication               : Application run failed

java.lang.IllegalArgumentException: Could not find class [com.example.boot.WrapperApplication__ApplicationContextInitializer]
Caused by: java.lang.ClassNotFoundException: com.example.boot.WrapperApplication__ApplicationContextInitializer
        at org.graalvm.nativeimage.builder/com.oracle.svm.core.hub.ClassForNameSupport.forName(ClassForNameSupport.java:123) ~[na:na]
        at org.graalvm.nativeimage.builder/com.oracle.svm.core.hub.ClassForNameSupport.forName(ClassForNameSupport.java:87) ~[na:na]
        at java.base@17.0.9/java.lang.Class.forName(DynamicHub.java:1322) ~[boot.exe:na]
        at java.base@17.0.9/java.lang.Class.forName(DynamicHub.java:1311) ~[boot.exe:na]
        at org.springframework.util.ClassUtils.forName(ClassUtils.java:291) ~[na:na]
        at org.springframework.util.ClassUtils.resolveClassName(ClassUtils.java:331) ~[na:na]
        ... 10 common frames omitted

It seems spring-boot:3.1.5:process-aot generates right code but at runtime it detectes WrapperApplication as primary application because SpringApplication.run(BootApplication.class); is run inside main method. If I rename method main in WrapperApplication to start it isn't reproduced.

Comment From: wilkinsona

Your wrapper-based approach has defeated SpringApplication's deduction of the main application class. It walks the stack looking for a main method, hence it working when you rename the method to start. I'm not sure that there's much we can do about this but you should be able to set the main application class explicitly to fix the problem:

SpringApplication app = new SpringApplication(BootApplication.class);
app.setMainApplicationClass(BootApplication.class);
app.run(args);

Comment From: hostmenow

@wilkinsona Thank you for quick answer and explanation.

Shouldn't explicitly defined application class here SpringApplication.run(BootApplication.class); have higher priority than hidden deduction logic based on name of static method? Also, without native profile that works fine. Shouldn't the deduction logic be the same?

The workaround with app.setMainApplicationClass(BootApplication.class); works. Thank you.

Comment From: philwebb

The arguments passed to SpringApplication.run do not necessarily have a main method so I think we need to keep the detection logic as it is. I think our MainClassFinder is finding com.example.boot.BootApplication because it has a @SpringBootApplication.

I wonder if we can change our addAotGeneratedInitializerIfNecessary to search the entire stack if mainApplicationClass doesn't have a generated __ApplicationContextInitializer class?

Comment From: philwebb

We discussed this today and decided we don't think we should walk the stack any further than the first main method. Our recommendation for a setup such as this is to either call setMainApplicationClass on SpringApplication or specify a specific main class in the build.