Skip to content

Commit f7f11a4

Browse files
committed
Merge branch '3.5.x'
Closes gh-48275
2 parents 949c227 + ae3408f commit f7f11a4

File tree

2 files changed

+94
-14
lines changed

2 files changed

+94
-14
lines changed

core/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootContextLoader.java

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package org.springframework.boot.test.context;
1818

1919
import java.lang.reflect.Method;
20+
import java.lang.reflect.Modifier;
2021
import java.util.ArrayList;
2122
import java.util.Arrays;
2223
import java.util.Collections;
@@ -140,7 +141,14 @@ private ApplicationContext loadContext(MergedContextConfiguration mergedConfig,
140141
}
141142
ContextLoaderHook hook = new ContextLoaderHook(mode, initializer,
142143
(application) -> configure(mergedConfig, application));
143-
return hook.runMain(() -> ReflectionUtils.invokeMethod(mainMethod, null, new Object[] { args }));
144+
return hook.runMain(() -> {
145+
if (mainMethod.getParameterCount() == 0) {
146+
ReflectionUtils.invokeMethod(mainMethod, null);
147+
}
148+
else {
149+
ReflectionUtils.invokeMethod(mainMethod, null, new Object[] { args });
150+
}
151+
});
144152
}
145153
SpringApplication application = getSpringApplication();
146154
configure(mergedConfig, application);
@@ -177,7 +185,7 @@ private void assertHasClassesOrLocations(MergedContextConfiguration mergedConfig
177185
}
178186

179187
private static @Nullable Method findMainMethod(@Nullable Class<?> type) {
180-
Method mainMethod = (type != null) ? ReflectionUtils.findMethod(type, "main", String[].class) : null;
188+
Method mainMethod = (type != null) ? findMainJavaMethod(type) : null;
181189
if (mainMethod == null && KotlinDetector.isKotlinPresent()) {
182190
try {
183191
Assert.state(type != null, "'type' must not be null");
@@ -191,6 +199,30 @@ private void assertHasClassesOrLocations(MergedContextConfiguration mergedConfig
191199
return mainMethod;
192200
}
193201

202+
private static @Nullable Method findMainJavaMethod(Class<?> type) {
203+
try {
204+
Method method = getMainMethod(type);
205+
if (Modifier.isStatic(method.getModifiers())) {
206+
method.setAccessible(true);
207+
return method;
208+
}
209+
}
210+
catch (Exception ex) {
211+
// Ignore
212+
}
213+
return null;
214+
}
215+
216+
private static Method getMainMethod(Class<?> type) throws NoSuchMethodException {
217+
try {
218+
return type.getDeclaredMethod("main", String[].class);
219+
}
220+
catch (NoSuchMethodException ex) {
221+
return type.getDeclaredMethod("main");
222+
}
223+
224+
}
225+
194226
private boolean isSpringBootConfiguration(Class<?> candidate) {
195227
return MergedAnnotations.from(candidate, SearchStrategy.TYPE_HIERARCHY)
196228
.isPresent(SpringBootConfiguration.class);

core/spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootContextLoaderTests.java

Lines changed: 60 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
import org.junit.jupiter.api.BeforeEach;
2626
import org.junit.jupiter.api.Disabled;
2727
import org.junit.jupiter.api.Test;
28+
import org.junit.jupiter.params.ParameterizedTest;
29+
import org.junit.jupiter.params.provider.ValueSource;
2830

2931
import org.springframework.aot.hint.RuntimeHints;
3032
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
@@ -199,10 +201,13 @@ void whenUseMainMethodWhenAvailableAndNoMainMethod() {
199201
assertThat(applicationContext.getEnvironment().getActiveProfiles()).isEmpty();
200202
}
201203

202-
@Test
203-
void whenUseMainMethodWhenAvailableAndMainMethod() {
204-
TestContext testContext = new ExposedTestContextManager(UseMainMethodWhenAvailableAndMainMethod.class)
205-
.getExposedTestContext();
204+
@ParameterizedTest
205+
@ValueSource(classes = { UsePublicMainMethodWhenAvailableAndMainMethod.class,
206+
UsePublicParameterlessMainMethodWhenAvailableAndMainMethod.class,
207+
UsePackagePrivateMainMethodWhenAvailableAndMainMethod.class,
208+
UsePackagePrivateParameterlessMainMethodWhenAvailableAndMainMethod.class })
209+
void whenUseMainMethodWhenAvailableAndMainMethod(Class<?> testClass) {
210+
TestContext testContext = new ExposedTestContextManager(testClass).getExposedTestContext();
206211
ApplicationContext applicationContext = testContext.getApplicationContext();
207212
assertThat(applicationContext.getEnvironment().getActiveProfiles()).contains("frommain");
208213
}
@@ -264,11 +269,11 @@ void whenMainMethodNotAvailableReturnsNoAotContribution() throws Exception {
264269
void whenMainMethodPresentRegisterReflectionHints() throws Exception {
265270
SpringBootContextLoader contextLoader = new SpringBootContextLoader();
266271
MergedContextConfiguration contextConfiguration = BootstrapUtils
267-
.resolveTestContextBootstrapper(UseMainMethodWhenAvailableAndMainMethod.class)
272+
.resolveTestContextBootstrapper(UsePublicMainMethodWhenAvailableAndMainMethod.class)
268273
.buildMergedContextConfiguration();
269274
RuntimeHints runtimeHints = new RuntimeHints();
270275
contextLoader.loadContextForAotProcessing(contextConfiguration, runtimeHints);
271-
assertThat(RuntimeHintsPredicates.reflection().onMethodInvocation(ConfigWithMain.class, "main"))
276+
assertThat(RuntimeHintsPredicates.reflection().onMethodInvocation(ConfigWithPublicMain.class, "main"))
272277
.accepts(runtimeHints);
273278
}
274279

@@ -371,12 +376,28 @@ static class UseMainMethodWhenAvailableAndNoMainMethod {
371376

372377
}
373378

374-
@SpringBootTest(classes = ConfigWithMain.class, useMainMethod = UseMainMethod.WHEN_AVAILABLE)
375-
static class UseMainMethodWhenAvailableAndMainMethod {
379+
@SpringBootTest(classes = ConfigWithPublicMain.class, useMainMethod = UseMainMethod.WHEN_AVAILABLE)
380+
static class UsePublicMainMethodWhenAvailableAndMainMethod {
381+
382+
}
383+
384+
@SpringBootTest(classes = ConfigWithPublicParameterlessMain.class, useMainMethod = UseMainMethod.WHEN_AVAILABLE)
385+
static class UsePublicParameterlessMainMethodWhenAvailableAndMainMethod {
376386

377387
}
378388

379-
@SpringBootTest(classes = ConfigWithMain.class, useMainMethod = UseMainMethod.NEVER)
389+
@SpringBootTest(classes = ConfigWithPackagePrivateMain.class, useMainMethod = UseMainMethod.WHEN_AVAILABLE)
390+
static class UsePackagePrivateMainMethodWhenAvailableAndMainMethod {
391+
392+
}
393+
394+
@SpringBootTest(classes = ConfigWithPackagePrivateParameterlessMain.class,
395+
useMainMethod = UseMainMethod.WHEN_AVAILABLE)
396+
static class UsePackagePrivateParameterlessMainMethodWhenAvailableAndMainMethod {
397+
398+
}
399+
400+
@SpringBootTest(classes = ConfigWithPublicMain.class, useMainMethod = UseMainMethod.NEVER)
380401
static class UseMainMethodNever {
381402

382403
}
@@ -392,7 +413,7 @@ static class NoMainMethodWithBeanThrowingException {
392413
}
393414

394415
@SpringBootTest(useMainMethod = UseMainMethod.ALWAYS)
395-
@ContextHierarchy({ @ContextConfiguration(classes = ConfigWithMain.class),
416+
@ContextHierarchy({ @ContextConfiguration(classes = ConfigWithPublicMain.class),
396417
@ContextConfiguration(classes = AnotherConfigWithMain.class) })
397418
static class UseMainMethodWithContextHierarchy {
398419

@@ -423,10 +444,37 @@ static class Config {
423444
}
424445

425446
@SpringBootConfiguration(proxyBeanMethods = false)
426-
public static class ConfigWithMain {
447+
public static class ConfigWithPublicMain {
427448

428449
public static void main(String[] args) {
429-
new SpringApplication(ConfigWithMain.class).run("--spring.profiles.active=frommain");
450+
new SpringApplication(ConfigWithPublicMain.class).run("--spring.profiles.active=frommain");
451+
}
452+
453+
}
454+
455+
@SpringBootConfiguration(proxyBeanMethods = false)
456+
public static class ConfigWithPublicParameterlessMain {
457+
458+
public static void main() {
459+
new SpringApplication(ConfigWithPublicMain.class).run("--spring.profiles.active=frommain");
460+
}
461+
462+
}
463+
464+
@SpringBootConfiguration(proxyBeanMethods = false)
465+
public static class ConfigWithPackagePrivateMain {
466+
467+
static void main(String[] args) {
468+
new SpringApplication(ConfigWithPublicMain.class).run("--spring.profiles.active=frommain");
469+
}
470+
471+
}
472+
473+
@SpringBootConfiguration(proxyBeanMethods = false)
474+
public static class ConfigWithPackagePrivateParameterlessMain {
475+
476+
static void main() {
477+
new SpringApplication(ConfigWithPublicMain.class).run("--spring.profiles.active=frommain");
430478
}
431479

432480
}

0 commit comments

Comments
 (0)