mirror of
https://github.com/spring-projects/spring-boot.git
synced 2026-09-26 11:39:14 +00:00
Detect JDK25-style main method in SpringBootTest
This commit adapts SpringBootTest when it has to use a main method to detect package private main method as well as main methods that do not have any arguments. Closes gh-48271
This commit is contained in:
+34
-2
@@ -17,6 +17,7 @@
|
||||
package org.springframework.boot.test.context;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@@ -136,7 +137,14 @@ public class SpringBootContextLoader extends AbstractContextLoader implements Ao
|
||||
}
|
||||
ContextLoaderHook hook = new ContextLoaderHook(mode, initializer,
|
||||
(application) -> configure(mergedConfig, application));
|
||||
return hook.runMain(() -> ReflectionUtils.invokeMethod(mainMethod, null, new Object[] { args }));
|
||||
return hook.runMain(() -> {
|
||||
if (mainMethod.getParameterCount() == 0) {
|
||||
ReflectionUtils.invokeMethod(mainMethod, null);
|
||||
}
|
||||
else {
|
||||
ReflectionUtils.invokeMethod(mainMethod, null, new Object[] { args });
|
||||
}
|
||||
});
|
||||
}
|
||||
SpringApplication application = getSpringApplication();
|
||||
configure(mergedConfig, application);
|
||||
@@ -172,7 +180,7 @@ public class SpringBootContextLoader extends AbstractContextLoader implements Ao
|
||||
}
|
||||
|
||||
private static Method findMainMethod(Class<?> type) {
|
||||
Method mainMethod = (type != null) ? ReflectionUtils.findMethod(type, "main", String[].class) : null;
|
||||
Method mainMethod = (type != null) ? findMainJavaMethod(type) : null;
|
||||
if (mainMethod == null && KotlinDetector.isKotlinPresent()) {
|
||||
try {
|
||||
Class<?> kotlinClass = ClassUtils.forName(type.getName() + "Kt", type.getClassLoader());
|
||||
@@ -185,6 +193,30 @@ public class SpringBootContextLoader extends AbstractContextLoader implements Ao
|
||||
return mainMethod;
|
||||
}
|
||||
|
||||
private static Method findMainJavaMethod(Class<?> type) {
|
||||
try {
|
||||
Method method = getMainMethod(type);
|
||||
if (Modifier.isStatic(method.getModifiers())) {
|
||||
method.setAccessible(true);
|
||||
return method;
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// Ignore
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Method getMainMethod(Class<?> type) throws NoSuchMethodException {
|
||||
try {
|
||||
return type.getDeclaredMethod("main", String[].class);
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
return type.getDeclaredMethod("main");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private boolean isSpringBootConfiguration(Class<?> candidate) {
|
||||
return MergedAnnotations.from(candidate, SearchStrategy.TYPE_HIERARCHY)
|
||||
.isPresent(SpringBootConfiguration.class);
|
||||
|
||||
+60
-12
@@ -24,6 +24,8 @@ import java.util.stream.Collectors;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
|
||||
@@ -199,10 +201,13 @@ class SpringBootContextLoaderTests {
|
||||
assertThat(applicationContext.getEnvironment().getActiveProfiles()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenUseMainMethodWhenAvailableAndMainMethod() {
|
||||
TestContext testContext = new ExposedTestContextManager(UseMainMethodWhenAvailableAndMainMethod.class)
|
||||
.getExposedTestContext();
|
||||
@ParameterizedTest
|
||||
@ValueSource(classes = { UsePublicMainMethodWhenAvailableAndMainMethod.class,
|
||||
UsePublicParameterlessMainMethodWhenAvailableAndMainMethod.class,
|
||||
UsePackagePrivateMainMethodWhenAvailableAndMainMethod.class,
|
||||
UsePackagePrivateParameterlessMainMethodWhenAvailableAndMainMethod.class })
|
||||
void whenUseMainMethodWhenAvailableAndMainMethod(Class<?> testClass) {
|
||||
TestContext testContext = new ExposedTestContextManager(testClass).getExposedTestContext();
|
||||
ApplicationContext applicationContext = testContext.getApplicationContext();
|
||||
assertThat(applicationContext.getEnvironment().getActiveProfiles()).contains("frommain");
|
||||
}
|
||||
@@ -264,11 +269,11 @@ class SpringBootContextLoaderTests {
|
||||
void whenMainMethodPresentRegisterReflectionHints() throws Exception {
|
||||
SpringBootContextLoader contextLoader = new SpringBootContextLoader();
|
||||
MergedContextConfiguration contextConfiguration = BootstrapUtils
|
||||
.resolveTestContextBootstrapper(UseMainMethodWhenAvailableAndMainMethod.class)
|
||||
.resolveTestContextBootstrapper(UsePublicMainMethodWhenAvailableAndMainMethod.class)
|
||||
.buildMergedContextConfiguration();
|
||||
RuntimeHints runtimeHints = new RuntimeHints();
|
||||
contextLoader.loadContextForAotProcessing(contextConfiguration, runtimeHints);
|
||||
assertThat(RuntimeHintsPredicates.reflection().onMethod(ConfigWithMain.class, "main").invoke())
|
||||
assertThat(RuntimeHintsPredicates.reflection().onMethod(ConfigWithPublicMain.class, "main").invoke())
|
||||
.accepts(runtimeHints);
|
||||
}
|
||||
|
||||
@@ -370,12 +375,28 @@ class SpringBootContextLoaderTests {
|
||||
|
||||
}
|
||||
|
||||
@SpringBootTest(classes = ConfigWithMain.class, useMainMethod = UseMainMethod.WHEN_AVAILABLE)
|
||||
static class UseMainMethodWhenAvailableAndMainMethod {
|
||||
@SpringBootTest(classes = ConfigWithPublicMain.class, useMainMethod = UseMainMethod.WHEN_AVAILABLE)
|
||||
static class UsePublicMainMethodWhenAvailableAndMainMethod {
|
||||
|
||||
}
|
||||
|
||||
@SpringBootTest(classes = ConfigWithMain.class, useMainMethod = UseMainMethod.NEVER)
|
||||
@SpringBootTest(classes = ConfigWithPublicParameterlessMain.class, useMainMethod = UseMainMethod.WHEN_AVAILABLE)
|
||||
static class UsePublicParameterlessMainMethodWhenAvailableAndMainMethod {
|
||||
|
||||
}
|
||||
|
||||
@SpringBootTest(classes = ConfigWithPackagePrivateMain.class, useMainMethod = UseMainMethod.WHEN_AVAILABLE)
|
||||
static class UsePackagePrivateMainMethodWhenAvailableAndMainMethod {
|
||||
|
||||
}
|
||||
|
||||
@SpringBootTest(classes = ConfigWithPackagePrivateParameterlessMain.class,
|
||||
useMainMethod = UseMainMethod.WHEN_AVAILABLE)
|
||||
static class UsePackagePrivateParameterlessMainMethodWhenAvailableAndMainMethod {
|
||||
|
||||
}
|
||||
|
||||
@SpringBootTest(classes = ConfigWithPublicMain.class, useMainMethod = UseMainMethod.NEVER)
|
||||
static class UseMainMethodNever {
|
||||
|
||||
}
|
||||
@@ -391,7 +412,7 @@ class SpringBootContextLoaderTests {
|
||||
}
|
||||
|
||||
@SpringBootTest(useMainMethod = UseMainMethod.ALWAYS)
|
||||
@ContextHierarchy({ @ContextConfiguration(classes = ConfigWithMain.class),
|
||||
@ContextHierarchy({ @ContextConfiguration(classes = ConfigWithPublicMain.class),
|
||||
@ContextConfiguration(classes = AnotherConfigWithMain.class) })
|
||||
static class UseMainMethodWithContextHierarchy {
|
||||
|
||||
@@ -422,10 +443,37 @@ class SpringBootContextLoaderTests {
|
||||
}
|
||||
|
||||
@SpringBootConfiguration(proxyBeanMethods = false)
|
||||
public static class ConfigWithMain {
|
||||
public static class ConfigWithPublicMain {
|
||||
|
||||
public static void main(String[] args) {
|
||||
new SpringApplication(ConfigWithMain.class).run("--spring.profiles.active=frommain");
|
||||
new SpringApplication(ConfigWithPublicMain.class).run("--spring.profiles.active=frommain");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@SpringBootConfiguration(proxyBeanMethods = false)
|
||||
public static class ConfigWithPublicParameterlessMain {
|
||||
|
||||
public static void main() {
|
||||
new SpringApplication(ConfigWithPublicMain.class).run("--spring.profiles.active=frommain");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@SpringBootConfiguration(proxyBeanMethods = false)
|
||||
public static class ConfigWithPackagePrivateMain {
|
||||
|
||||
static void main(String[] args) {
|
||||
new SpringApplication(ConfigWithPublicMain.class).run("--spring.profiles.active=frommain");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@SpringBootConfiguration(proxyBeanMethods = false)
|
||||
public static class ConfigWithPackagePrivateParameterlessMain {
|
||||
|
||||
static void main() {
|
||||
new SpringApplication(ConfigWithPublicMain.class).run("--spring.profiles.active=frommain");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user