Skip to content

Commit 28d699f

Browse files
committed
Detect Java 25+ style methods with AOT processing
Closes gh-47780
1 parent df8ba4c commit 28d699f

File tree

2 files changed

+109
-22
lines changed

2 files changed

+109
-22
lines changed

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplicationAotProcessor.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,27 @@ public SpringApplicationAotProcessor(Class<?> application, Settings settings, St
5858
@Override
5959
protected GenericApplicationContext prepareApplicationContext(Class<?> application) {
6060
return new AotProcessorHook(application).run(() -> {
61-
Method mainMethod = application.getMethod("main", String[].class);
62-
return ReflectionUtils.invokeMethod(mainMethod, null, new Object[] { this.applicationArgs });
61+
Method mainMethod = getMainMethod(application);
62+
mainMethod.setAccessible(true);
63+
if (mainMethod.getParameterCount() == 0) {
64+
ReflectionUtils.invokeMethod(mainMethod, null);
65+
}
66+
else {
67+
ReflectionUtils.invokeMethod(mainMethod, null, new Object[] { this.applicationArgs });
68+
}
69+
return Void.class;
6370
});
6471
}
6572

73+
private static Method getMainMethod(Class<?> application) throws Exception {
74+
try {
75+
return application.getDeclaredMethod("main", String[].class);
76+
}
77+
catch (NoSuchMethodException ex) {
78+
return application.getDeclaredMethod("main");
79+
}
80+
}
81+
6682
public static void main(String[] args) throws Exception {
6783
int requiredArgs = 6;
6884
Assert.state(args.length >= requiredArgs, () -> "Usage: " + SpringApplicationAotProcessor.class.getName()

spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationAotProcessorTests.java

Lines changed: 91 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -36,20 +36,21 @@
3636
*/
3737
class SpringApplicationAotProcessorTests {
3838

39+
private static final ApplicationInvoker invoker = new ApplicationInvoker();
40+
3941
@BeforeEach
4042
void setup() {
41-
SampleApplication.argsHolder = null;
42-
SampleApplication.postRunInvoked = false;
43+
invoker.clean();
4344
}
4445

4546
@Test
46-
void processApplicationInvokesRunMethod(@TempDir Path directory) {
47+
void processApplicationInvokesMainMethod(@TempDir Path directory) {
4748
String[] arguments = new String[] { "1", "2" };
48-
SpringApplicationAotProcessor processor = new SpringApplicationAotProcessor(SampleApplication.class,
49+
SpringApplicationAotProcessor processor = new SpringApplicationAotProcessor(PublicMainMethod.class,
4950
settings(directory), arguments);
5051
processor.process();
51-
assertThat(SampleApplication.argsHolder).isEqualTo(arguments);
52-
assertThat(SampleApplication.postRunInvoked).isFalse();
52+
assertThat(ApplicationInvoker.argsHolder).isEqualTo(arguments);
53+
assertThat(ApplicationInvoker.postRunInvoked).isFalse();
5354
}
5455

5556
@Test
@@ -62,23 +63,53 @@ void processApplicationWithMainMethodThatDoesNotRun(@TempDir Path directory) {
6263
}
6364

6465
@Test
65-
void invokeMainParsesArgumentsAndInvokesRunMethod(@TempDir Path directory) throws Exception {
66-
String[] mainArguments = new String[] { SampleApplication.class.getName(),
66+
void invokeMainParsesArgumentsAndInvokesMainMethod(@TempDir Path directory) throws Exception {
67+
String[] mainArguments = new String[] { PublicMainMethod.class.getName(),
68+
directory.resolve("source").toString(), directory.resolve("resource").toString(),
69+
directory.resolve("class").toString(), "com.example", "example", "1", "2" };
70+
SpringApplicationAotProcessor.main(mainArguments);
71+
assertThat(ApplicationInvoker.argsHolder).containsExactly("1", "2");
72+
assertThat(ApplicationInvoker.postRunInvoked).isFalse();
73+
}
74+
75+
@Test
76+
void invokeMainParsesArgumentsAndInvokesPackagePrivateMainMethod(@TempDir Path directory) throws Exception {
77+
String[] mainArguments = new String[] { PackagePrivateMainMethod.class.getName(),
6778
directory.resolve("source").toString(), directory.resolve("resource").toString(),
6879
directory.resolve("class").toString(), "com.example", "example", "1", "2" };
6980
SpringApplicationAotProcessor.main(mainArguments);
70-
assertThat(SampleApplication.argsHolder).containsExactly("1", "2");
71-
assertThat(SampleApplication.postRunInvoked).isFalse();
81+
assertThat(ApplicationInvoker.argsHolder).containsExactly("1", "2");
82+
assertThat(ApplicationInvoker.postRunInvoked).isFalse();
83+
}
84+
85+
@Test
86+
void invokeMainParsesArgumentsAndInvokesParameterLessMainMethod(@TempDir Path directory) throws Exception {
87+
String[] mainArguments = new String[] { PublicParameterlessMainMethod.class.getName(),
88+
directory.resolve("source").toString(), directory.resolve("resource").toString(),
89+
directory.resolve("class").toString(), "com.example", "example", "1", "2" };
90+
SpringApplicationAotProcessor.main(mainArguments);
91+
assertThat(ApplicationInvoker.argsHolder).isNull();
92+
assertThat(ApplicationInvoker.postRunInvoked).isFalse();
93+
}
94+
95+
@Test
96+
void invokeMainParsesArgumentsAndInvokesPackagePrivateRunMethod(@TempDir Path directory) throws Exception {
97+
String[] mainArguments = new String[] { PackagePrivateParameterlessMainMethod.class.getName(),
98+
directory.resolve("source").toString(), directory.resolve("resource").toString(),
99+
directory.resolve("class").toString(), "com.example", "example", "1", "2" };
100+
SpringApplicationAotProcessor.main(mainArguments);
101+
assertThat(ApplicationInvoker.argsHolder).isNull();
102+
assertThat(ApplicationInvoker.postRunInvoked).isFalse();
72103
}
73104

74105
@Test
75106
void invokeMainParsesArgumentsAndInvokesRunMethodWithoutGroupId(@TempDir Path directory) throws Exception {
76-
String[] mainArguments = new String[] { SampleApplication.class.getName(),
107+
String[] mainArguments = new String[] { PublicMainMethod.class.getName(),
77108
directory.resolve("source").toString(), directory.resolve("resource").toString(),
78109
directory.resolve("class").toString(), "", "example", "1", "2" };
79110
SpringApplicationAotProcessor.main(mainArguments);
80-
assertThat(SampleApplication.argsHolder).containsExactly("1", "2");
81-
assertThat(SampleApplication.postRunInvoked).isFalse();
111+
assertThat(ApplicationInvoker.argsHolder).containsExactly("1", "2");
112+
assertThat(ApplicationInvoker.postRunInvoked).isFalse();
82113
}
83114

84115
@Test
@@ -99,16 +130,37 @@ private Settings settings(Path directory) {
99130
}
100131

101132
@Configuration(proxyBeanMethods = false)
102-
public static class SampleApplication {
133+
public static class PublicMainMethod {
103134

104-
public static String[] argsHolder;
135+
public static void main(String[] args) {
136+
invoker.invoke(args, () -> SpringApplication.run(PublicMainMethod.class, args));
137+
}
105138

106-
public static boolean postRunInvoked;
139+
}
107140

108-
public static void main(String[] args) {
109-
argsHolder = args;
110-
SpringApplication.run(SampleApplication.class, args);
111-
postRunInvoked = true;
141+
@Configuration(proxyBeanMethods = false)
142+
public static class PackagePrivateMainMethod {
143+
144+
static void main(String[] args) {
145+
invoker.invoke(args, () -> SpringApplication.run(PackagePrivateMainMethod.class, args));
146+
}
147+
148+
}
149+
150+
@Configuration(proxyBeanMethods = false)
151+
public static class PublicParameterlessMainMethod {
152+
153+
public static void main() {
154+
invoker.invoke(null, () -> SpringApplication.run(PublicParameterlessMainMethod.class));
155+
}
156+
157+
}
158+
159+
@Configuration(proxyBeanMethods = false)
160+
public static class PackagePrivateParameterlessMainMethod {
161+
162+
static void main() {
163+
invoker.invoke(null, () -> SpringApplication.run(PackagePrivateParameterlessMainMethod.class));
112164
}
113165

114166
}
@@ -121,4 +173,23 @@ public static void main(String[] args) {
121173

122174
}
123175

176+
private static final class ApplicationInvoker {
177+
178+
public static String[] argsHolder;
179+
180+
public static boolean postRunInvoked;
181+
182+
void invoke(String[] args, Runnable applicationRun) {
183+
argsHolder = args;
184+
applicationRun.run();
185+
postRunInvoked = true;
186+
}
187+
188+
void clean() {
189+
argsHolder = null;
190+
postRunInvoked = false;
191+
}
192+
193+
}
194+
124195
}

0 commit comments

Comments
 (0)