From bb23ef72b6a72fd5bfedb4775646072510533313 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Fri, 7 Aug 2026 14:15:02 +0200 Subject: [PATCH] Add testClasspath option to run and start goals Deprecate the `useTestClasspath` flag in favor of a `testClasspath` parameter on the `run` and `start` goals. It accepts `off`, `dependencies`, or `all`, with `all` also adding the project's test classes directory to the classpath so that a main class located in `src/test/java` can be found and run, matching the `test-run` goal's existing behaviour. Closes gh-36115 --- .../boot/maven/RunIntegrationTests.java | 23 ++++++++ .../boot/maven/StartStopIntegrationTests.java | 12 +++- .../projects/run-test-classpath-all/pom.xml | 33 +++++++++++ .../test/java/org/test/SampleApplication.java | 33 +++++++++++ .../run-test-classpath-dependencies/pom.xml | 33 +++++++++++ .../main/java/org/test/SampleApplication.java | 38 ++++++++++++ .../src/test/java/org/test/SampleTest.java | 21 +++++++ .../projects/run-test-classpath-off/pom.xml | 33 +++++++++++ .../main/java/org/test/SampleApplication.java | 39 ++++++++++++ .../src/test/java/org/test/SampleTest.java | 21 +++++++ .../intTest/projects/start-stop-test/pom.xml | 59 +++++++++++++++++++ .../java/org/test/SpringApplicationAdmin.java | 37 ++++++++++++ .../test/SpringApplicationAdminMXBean.java | 25 ++++++++ .../test/java/org/test/SampleApplication.java | 54 +++++++++++++++++ .../boot/maven/AbstractRunMojo.java | 50 +++++++++++++++- .../springframework/boot/maven/RunMojo.java | 34 +++++++++-- .../springframework/boot/maven/StartMojo.java | 33 +++++++++-- .../boot/maven/TestRunMojo.java | 20 +------ 18 files changed, 568 insertions(+), 30 deletions(-) create mode 100644 build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-test-classpath-all/pom.xml create mode 100644 build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-test-classpath-all/src/test/java/org/test/SampleApplication.java create mode 100644 build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-test-classpath-dependencies/pom.xml create mode 100644 build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-test-classpath-dependencies/src/main/java/org/test/SampleApplication.java create mode 100644 build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-test-classpath-dependencies/src/test/java/org/test/SampleTest.java create mode 100644 build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-test-classpath-off/pom.xml create mode 100644 build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-test-classpath-off/src/main/java/org/test/SampleApplication.java create mode 100644 build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-test-classpath-off/src/test/java/org/test/SampleTest.java create mode 100644 build-plugin/spring-boot-maven-plugin/src/intTest/projects/start-stop-test/pom.xml create mode 100644 build-plugin/spring-boot-maven-plugin/src/intTest/projects/start-stop-test/src/main/java/org/test/SpringApplicationAdmin.java create mode 100644 build-plugin/spring-boot-maven-plugin/src/intTest/projects/start-stop-test/src/main/java/org/test/SpringApplicationAdminMXBean.java create mode 100644 build-plugin/spring-boot-maven-plugin/src/intTest/projects/start-stop-test/src/test/java/org/test/SampleApplication.java diff --git a/build-plugin/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/RunIntegrationTests.java b/build-plugin/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/RunIntegrationTests.java index bf9e6a214e3..f5d0bd15e53 100644 --- a/build-plugin/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/RunIntegrationTests.java +++ b/build-plugin/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/RunIntegrationTests.java @@ -95,8 +95,31 @@ class RunIntegrationTests { } @TestTemplate + @Deprecated(since = "4.2.0", forRemoval = true) void whenUseTestClasspathIsEnabledTheApplicationHasTestDependenciesOnItsClasspath(MavenBuild mavenBuild) { mavenBuild.project("run-use-test-classpath") + .goals("spring-boot:run") + .execute((project) -> assertThat(buildLog(project)).contains("I haz been run") + .contains("useTestClasspath is deprecated, use testClasspath instead.")); + } + + @TestTemplate + void whenTestClasspathIsDependenciesTheApplicationHasTestDependenciesOnItsClasspath(MavenBuild mavenBuild) { + mavenBuild.project("run-test-classpath-dependencies") + .goals("spring-boot:run") + .execute((project) -> assertThat(buildLog(project)).contains("I haz been run")); + } + + @TestTemplate + void whenTestClasspathIsAllTheApplicationHasTestAndClassesDependenciesOnItsClasspath(MavenBuild mavenBuild) { + mavenBuild.project("run-test-classpath-all") + .goals("spring-boot:run") + .execute((project) -> assertThat(buildLog(project)).contains("I haz been run")); + } + + @TestTemplate + void whenTestClasspathIsOffTheApplicationHasNeitherTestNorClassesDependenciesOnItsClasspath(MavenBuild mavenBuild) { + mavenBuild.project("run-test-classpath-off") .goals("spring-boot:run") .execute((project) -> assertThat(buildLog(project)).contains("I haz been run")); } diff --git a/build-plugin/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/StartStopIntegrationTests.java b/build-plugin/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/StartStopIntegrationTests.java index 5e6b8efe1b0..acd0b6c215e 100644 --- a/build-plugin/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/StartStopIntegrationTests.java +++ b/build-plugin/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/StartStopIntegrationTests.java @@ -34,7 +34,17 @@ class StartStopIntegrationTests { @TestTemplate void startStopWaitsForApplicationToBeReadyAndThenRequestsShutdown(MavenBuild mavenBuild) { - mavenBuild.project("start-stop") + testStartStop(mavenBuild, "start-stop"); + + } + + @TestTemplate + void startStopWithTestClasspathWaitsForApplicationToBeReadyAndThenRequestsShutdown(MavenBuild mavenBuild) { + testStartStop(mavenBuild, "start-stop-test"); + } + + private void testStartStop(MavenBuild mavenBuild, String projectId) { + mavenBuild.project(projectId) .goals("verify") .execute((project) -> assertThat(buildLog(project)).contains("isReady: true") .contains("Shutdown requested")); diff --git a/build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-test-classpath-all/pom.xml b/build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-test-classpath-all/pom.xml new file mode 100644 index 00000000000..4fedfc6053c --- /dev/null +++ b/build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-test-classpath-all/pom.xml @@ -0,0 +1,33 @@ + + + 4.0.0 + org.springframework.boot.maven.it + run-test-classpath-all + 0.0.1.BUILD-SNAPSHOT + + UTF-8 + @java.version@ + @java.version@ + + + + + @project.groupId@ + @project.artifactId@ + @project.version@ + + all + + + + + + + org.springframework + spring-context + @spring-framework.version@ + test + + + diff --git a/build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-test-classpath-all/src/test/java/org/test/SampleApplication.java b/build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-test-classpath-all/src/test/java/org/test/SampleApplication.java new file mode 100644 index 00000000000..19e05c51e08 --- /dev/null +++ b/build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-test-classpath-all/src/test/java/org/test/SampleApplication.java @@ -0,0 +1,33 @@ +/* + * Copyright 2012-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.test; + +public class SampleApplication { + + public static void main(String[] args) { + + Class appContext = null; + try { + appContext = Class.forName("org.springframework.context.ApplicationContext"); + } + catch (ClassNotFoundException e) { + throw new IllegalStateException("Test dependencies not added to classpath", e); + } + System.out.println("I haz been run"); + } + +} diff --git a/build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-test-classpath-dependencies/pom.xml b/build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-test-classpath-dependencies/pom.xml new file mode 100644 index 00000000000..5bfc72a9110 --- /dev/null +++ b/build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-test-classpath-dependencies/pom.xml @@ -0,0 +1,33 @@ + + + 4.0.0 + org.springframework.boot.maven.it + run-test-classpath-dependencies + 0.0.1.BUILD-SNAPSHOT + + UTF-8 + @java.version@ + @java.version@ + + + + + @project.groupId@ + @project.artifactId@ + @project.version@ + + dependencies + + + + + + + org.springframework + spring-context + @spring-framework.version@ + test + + + diff --git a/build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-test-classpath-dependencies/src/main/java/org/test/SampleApplication.java b/build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-test-classpath-dependencies/src/main/java/org/test/SampleApplication.java new file mode 100644 index 00000000000..e2f44e45920 --- /dev/null +++ b/build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-test-classpath-dependencies/src/main/java/org/test/SampleApplication.java @@ -0,0 +1,38 @@ +/* + * Copyright 2012-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.test; + +public class SampleApplication { + + public static void main(String[] args) { + try { + Class.forName("org.springframework.context.ApplicationContext"); + } + catch (ClassNotFoundException e) { + throw new IllegalStateException("Test dependencies not added to classpath", e); + } + try { + Class.forName("org.test.SampleTest"); + throw new IllegalStateException("Test classes should not have been added to classpath"); + } + catch (ClassNotFoundException e) { + // OK + } + System.out.println("I haz been run"); + } + +} diff --git a/build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-test-classpath-dependencies/src/test/java/org/test/SampleTest.java b/build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-test-classpath-dependencies/src/test/java/org/test/SampleTest.java new file mode 100644 index 00000000000..0fd0a1474a3 --- /dev/null +++ b/build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-test-classpath-dependencies/src/test/java/org/test/SampleTest.java @@ -0,0 +1,21 @@ +/* + * Copyright 2012-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.test; + +public class SampleTest { + +} diff --git a/build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-test-classpath-off/pom.xml b/build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-test-classpath-off/pom.xml new file mode 100644 index 00000000000..69d1b00a2fd --- /dev/null +++ b/build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-test-classpath-off/pom.xml @@ -0,0 +1,33 @@ + + + 4.0.0 + org.springframework.boot.maven.it + run-test-classpath-off + 0.0.1.BUILD-SNAPSHOT + + UTF-8 + @java.version@ + @java.version@ + + + + + @project.groupId@ + @project.artifactId@ + @project.version@ + + off + + + + + + + org.springframework + spring-context + @spring-framework.version@ + test + + + diff --git a/build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-test-classpath-off/src/main/java/org/test/SampleApplication.java b/build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-test-classpath-off/src/main/java/org/test/SampleApplication.java new file mode 100644 index 00000000000..725d88351ca --- /dev/null +++ b/build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-test-classpath-off/src/main/java/org/test/SampleApplication.java @@ -0,0 +1,39 @@ +/* + * Copyright 2012-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.test; + +public class SampleApplication { + + public static void main(String[] args) { + try { + Class.forName("org.springframework.context.ApplicationContext"); + throw new IllegalStateException("Test dependencies should not have been added to classpath"); + } + catch (ClassNotFoundException e) { + // OK + } + try { + Class.forName("org.test.SampleTest"); + throw new IllegalStateException("Test classes should not have been added to classpath"); + } + catch (ClassNotFoundException e) { + // OK + } + System.out.println("I haz been run"); + } + +} diff --git a/build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-test-classpath-off/src/test/java/org/test/SampleTest.java b/build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-test-classpath-off/src/test/java/org/test/SampleTest.java new file mode 100644 index 00000000000..0fd0a1474a3 --- /dev/null +++ b/build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-test-classpath-off/src/test/java/org/test/SampleTest.java @@ -0,0 +1,21 @@ +/* + * Copyright 2012-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.test; + +public class SampleTest { + +} diff --git a/build-plugin/spring-boot-maven-plugin/src/intTest/projects/start-stop-test/pom.xml b/build-plugin/spring-boot-maven-plugin/src/intTest/projects/start-stop-test/pom.xml new file mode 100644 index 00000000000..6613cb47a99 --- /dev/null +++ b/build-plugin/spring-boot-maven-plugin/src/intTest/projects/start-stop-test/pom.xml @@ -0,0 +1,59 @@ + + + 4.0.0 + org.springframework.boot.maven.it + start-stop-test + 0.0.1.BUILD-SNAPSHOT + + UTF-8 + @java.version@ + @java.version@ + + + + + org.codehaus.mojo + build-helper-maven-plugin + @build-helper-maven-plugin.version@ + + + reserve-jmx-port + + reserve-network-port + + process-resources + + + jmx.port + + + + + + + @project.groupId@ + @project.artifactId@ + @project.version@ + + + pre-integration-test + + start + + + + post-integration-test + + stop + + + + + ${jmx.port} + all + + + + + diff --git a/build-plugin/spring-boot-maven-plugin/src/intTest/projects/start-stop-test/src/main/java/org/test/SpringApplicationAdmin.java b/build-plugin/spring-boot-maven-plugin/src/intTest/projects/start-stop-test/src/main/java/org/test/SpringApplicationAdmin.java new file mode 100644 index 00000000000..b56865a700c --- /dev/null +++ b/build-plugin/spring-boot-maven-plugin/src/intTest/projects/start-stop-test/src/main/java/org/test/SpringApplicationAdmin.java @@ -0,0 +1,37 @@ +/* + * Copyright 2012-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.test; + +final class SpringApplicationAdmin implements SpringApplicationAdminMXBean { + + boolean ready; + + boolean shutdownInvoked; + + @Override + public boolean isReady() { + System.out.println("isReady: " + this.ready); + return this.ready; + } + + @Override + public void shutdown() { + this.shutdownInvoked = true; + System.out.println("Shutdown requested"); + } + +} \ No newline at end of file diff --git a/build-plugin/spring-boot-maven-plugin/src/intTest/projects/start-stop-test/src/main/java/org/test/SpringApplicationAdminMXBean.java b/build-plugin/spring-boot-maven-plugin/src/intTest/projects/start-stop-test/src/main/java/org/test/SpringApplicationAdminMXBean.java new file mode 100644 index 00000000000..8c240fdaab6 --- /dev/null +++ b/build-plugin/spring-boot-maven-plugin/src/intTest/projects/start-stop-test/src/main/java/org/test/SpringApplicationAdminMXBean.java @@ -0,0 +1,25 @@ +/* + * Copyright 2012-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.test; + +public interface SpringApplicationAdminMXBean { + + boolean isReady(); + + void shutdown(); + +} \ No newline at end of file diff --git a/build-plugin/spring-boot-maven-plugin/src/intTest/projects/start-stop-test/src/test/java/org/test/SampleApplication.java b/build-plugin/spring-boot-maven-plugin/src/intTest/projects/start-stop-test/src/test/java/org/test/SampleApplication.java new file mode 100644 index 00000000000..f2008431c35 --- /dev/null +++ b/build-plugin/spring-boot-maven-plugin/src/intTest/projects/start-stop-test/src/test/java/org/test/SampleApplication.java @@ -0,0 +1,54 @@ +/* + * Copyright 2012-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.test; + +import java.lang.management.ManagementFactory; + +import javax.management.MBeanServer; +import javax.management.ObjectName; + +/** + * This sample app simulates the JMX Mbean that is exposed by the Spring Boot application. + */ +public class SampleApplication { + + private static final Object lock = new Object(); + + public static void main(String[] args) throws Exception { + MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); + ObjectName name = new ObjectName( + "org.springframework.boot:type=Admin,name=SpringApplication"); + SpringApplicationAdmin mbean = new SpringApplicationAdmin(); + mbs.registerMBean(mbean, name); + + // Flag the app as ready + mbean.ready = true; + + int waitAttempts = 0; + while (!mbean.shutdownInvoked) { + if (waitAttempts > 30) { + throw new IllegalStateException( + "Shutdown should have been invoked by now"); + } + synchronized (lock) { + lock.wait(250); + } + waitAttempts++; + } + } + +} diff --git a/build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java b/build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java index 08feb075567..cb1ce5f2646 100644 --- a/build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java +++ b/build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java @@ -205,6 +205,16 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { @SuppressWarnings("NullAway.Init") private File classesDirectory; + /** + * Directory containing the test classes and resource files that can be included when + * running the application. + * + * @since 4.2.0 + */ + @Parameter(defaultValue = "${project.build.testOutputDirectory}", required = true) + @SuppressWarnings("NullAway.Init") + private File testClassesDirectory; + /** * Skip the execution. * @@ -241,10 +251,19 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { * @since 3.1.0 */ protected List getClassesDirectories() { - return List.of(this.classesDirectory); + List classesDirectories = new ArrayList<>(); + if (testClasspath() == TestClasspath.ALL) { + classesDirectories.add(this.testClassesDirectory); + } + classesDirectories.add(this.classesDirectory); + return Collections.unmodifiableList(classesDirectories); } - protected abstract boolean isUseTestClasspath(); + /** + * Return the {@link TestClasspath} strategy to use. + * @return the test classpath strategy + */ + protected abstract TestClasspath testClasspath(); private void run(String startClassName) throws MojoExecutionException, MojoFailureException { List args = new ArrayList<>(); @@ -416,7 +435,9 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { } private void addDependencies(List urls) throws MalformedURLException, MojoExecutionException { - Set artifacts = (isUseTestClasspath()) ? filterDependencies(this.project.getArtifacts()) + TestClasspath testClasspath = testClasspath(); + Set artifacts = ((testClasspath == TestClasspath.ALL || testClasspath == TestClasspath.DEPENDENCIES)) + ? filterDependencies(this.project.getArtifacts()) : filterDependencies(this.project.getArtifacts(), new ExcludeTestScopeArtifactFilter()); for (Artifact artifact : artifacts) { if (artifact.getFile() != null) { @@ -432,4 +453,27 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { } } + /** + * Strategies to handle the test classpath when running an application. + */ + protected enum TestClasspath { + + /** + * Do not include the test classpath at all. + */ + OFF, + + /** + * Include only dependencies with test scope. + */ + DEPENDENCIES, + + /** + * Include the full test classpath (test classes and dependencies with test + * scope). + */ + ALL + + } + } diff --git a/build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RunMojo.java b/build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RunMojo.java index 8992ed3d55f..ee6332ca076 100644 --- a/build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RunMojo.java +++ b/build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RunMojo.java @@ -18,6 +18,7 @@ package org.springframework.boot.maven; import java.io.File; import java.util.List; +import java.util.Locale; import java.util.Map; import javax.inject.Inject; @@ -30,6 +31,7 @@ import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.ResolutionScope; import org.apache.maven.toolchain.ToolchainManager; +import org.jspecify.annotations.Nullable; import org.springframework.boot.loader.tools.RunProcess; @@ -57,9 +59,24 @@ public class RunMojo extends AbstractRunMojo { /** * Flag to include the test classpath when running. * @since 1.3.0 + * @deprecated since 4.2.0 for removal in 4.4.0 in favor of {@code testClasspath} */ - @Parameter(property = "spring-boot.run.useTestClasspath", defaultValue = "false") - private boolean useTestClasspath; + @Parameter(property = "spring-boot.run.useTestClasspath") + @Deprecated(since = "4.2.0", forRemoval = true) + private @Nullable Boolean useTestClasspath; + + /** + * Strategy to determine how the test classpath should be included when running the + * application. Available values are {@code off} to not include the test classpath at + * all, {@code dependencies} to include only dependencies with test scope, and + * {@code all} to include the full test classpath (test classes and dependencies with + * test scope). + * @since 4.2.0 + */ + @Parameter(property = "spring-boot.run.testClasspath", defaultValue = "off") + private String testClasspath = "off"; + + private @Nullable TestClasspath resolvedTestClasspath; @Inject public RunMojo(ToolchainManager toolchainManager) { @@ -85,8 +102,17 @@ public class RunMojo extends AbstractRunMojo { } @Override - protected boolean isUseTestClasspath() { - return this.useTestClasspath; + protected TestClasspath testClasspath() { + if (this.resolvedTestClasspath == null) { + if (this.useTestClasspath != null) { + getLog().warn("useTestClasspath is deprecated, use testClasspath instead."); + this.resolvedTestClasspath = (this.useTestClasspath) ? TestClasspath.DEPENDENCIES : TestClasspath.OFF; + } + else { + this.resolvedTestClasspath = TestClasspath.valueOf(this.testClasspath.toUpperCase(Locale.ROOT)); + } + } + return this.resolvedTestClasspath; } private static final class RunProcessKiller implements Runnable { diff --git a/build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/StartMojo.java b/build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/StartMojo.java index 728e663546c..39fd8a6605f 100644 --- a/build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/StartMojo.java +++ b/build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/StartMojo.java @@ -21,6 +21,7 @@ import java.io.IOException; import java.net.ConnectException; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.concurrent.Callable; @@ -91,9 +92,24 @@ public class StartMojo extends AbstractRunMojo { /** * Flag to include the test classpath when running. + * @deprecated since 4.2.0 for removal in 4.4.0 in favor of {@code testClasspath} */ - @Parameter(property = "spring-boot.run.useTestClasspath", defaultValue = "false") - private boolean useTestClasspath; + @Parameter(property = "spring-boot.run.useTestClasspath") + @Deprecated(since = "4.2.0", forRemoval = true) + private @Nullable Boolean useTestClasspath; + + /** + * Strategy to determine how the test classpath should be included when running the + * application. Available values are {@code off} to not include the test classpath at + * all, {@code dependencies} to include only dependencies with test scope, and + * {@code all} to include the full test classpath (test classes and dependencies with + * test scope). + * @since 4.2.0 + */ + @Parameter(property = "spring-boot.run.testClasspath", defaultValue = "off") + private String testClasspath = "off"; + + private @Nullable TestClasspath resolvedTestClasspath; @Inject public StartMojo(ToolchainManager toolchainManager) { @@ -205,8 +221,17 @@ public class StartMojo extends AbstractRunMojo { } @Override - protected boolean isUseTestClasspath() { - return this.useTestClasspath; + protected TestClasspath testClasspath() { + if (this.resolvedTestClasspath == null) { + if (this.useTestClasspath != null) { + getLog().warn("useTestClasspath is deprecated, use testClasspath instead."); + this.resolvedTestClasspath = (this.useTestClasspath) ? TestClasspath.DEPENDENCIES : TestClasspath.OFF; + } + else { + this.resolvedTestClasspath = TestClasspath.valueOf(this.testClasspath.toUpperCase(Locale.ROOT)); + } + } + return this.resolvedTestClasspath; } private class CreateJmxConnector implements Callable<@Nullable JMXConnector> { diff --git a/build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/TestRunMojo.java b/build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/TestRunMojo.java index 4be0c6185e6..9ece33a41c6 100644 --- a/build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/TestRunMojo.java +++ b/build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/TestRunMojo.java @@ -17,7 +17,6 @@ package org.springframework.boot.maven; import java.io.File; -import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -57,29 +56,14 @@ public class TestRunMojo extends AbstractRunMojo { @Parameter(property = "spring-boot.test-run.optimizedLaunch", defaultValue = "true") private boolean optimizedLaunch; - /** - * Directory containing the test classes and resource files that should be used to run - * the application. - */ - @Parameter(defaultValue = "${project.build.testOutputDirectory}", required = true) - @SuppressWarnings("NullAway.Init") - private File testClassesDirectory; - @Inject public TestRunMojo(ToolchainManager toolchainManager) { super(toolchainManager); } @Override - protected List getClassesDirectories() { - ArrayList classesDirectories = new ArrayList<>(super.getClassesDirectories()); - classesDirectories.add(0, this.testClassesDirectory); - return classesDirectories; - } - - @Override - protected boolean isUseTestClasspath() { - return true; + protected TestClasspath testClasspath() { + return TestClasspath.ALL; } @Override