From 99cf0e3cfe60cc3e5abd569c7bc76d37c56676f1 Mon Sep 17 00:00:00 2001 From: academey Date: Thu, 24 Jul 2025 08:54:21 +0900 Subject: [PATCH] Exclude spring-boot-devtools from AOT processing with Maven Previously, spring-boot-devtools was only excluded from native images built with Gradle but not with Maven. This inconsistency meant that Maven builds would include devtools in the AOT processing classpath and in the native image, causing build failures. This commit harmonizes the situation and excludes devtools in a similar fashion with Maven. See gh-46533 Signed-off-by: academey --- .../springframework/boot/maven/AotTests.java | 22 +++++++ .../projects/aot-exclude-devtools/pom.xml | 48 +++++++++++++++ .../main/java/org/test/SampleApplication.java | 29 +++++++++ .../aot-test-exclude-devtools/pom.xml | 60 +++++++++++++++++++ .../main/java/org/test/SampleApplication.java | 29 +++++++++ .../java/org/test/SampleApplicationTests.java | 29 +++++++++ .../boot/maven/ProcessAotMojo.java | 2 +- .../boot/maven/ProcessTestAotMojo.java | 2 +- .../spring-boot-starter-parent/build.gradle | 12 ++++ 9 files changed, 231 insertions(+), 2 deletions(-) create mode 100644 build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-exclude-devtools/pom.xml create mode 100644 build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-exclude-devtools/src/main/java/org/test/SampleApplication.java create mode 100644 build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-test-exclude-devtools/pom.xml create mode 100644 build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-test-exclude-devtools/src/main/java/org/test/SampleApplication.java create mode 100644 build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-test-exclude-devtools/src/test/java/org/test/SampleApplicationTests.java diff --git a/build-plugin/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/AotTests.java b/build-plugin/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/AotTests.java index a96ace27fc8..93664d0acb9 100644 --- a/build-plugin/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/AotTests.java +++ b/build-plugin/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/AotTests.java @@ -195,4 +195,26 @@ class AotTests { return contentOf(new File(project, "target/build.log")); } + @TestTemplate + void whenAotRunsWithDevtoolsInClasspathItIsExcluded(MavenBuild mavenBuild) { + mavenBuild.project("aot-exclude-devtools").goals("package").execute((project) -> { + Path aotDirectory = project.toPath().resolve("target/spring-aot/main"); + assertThat(aotDirectory).exists(); + Path sourcesDirectory = aotDirectory.resolve("sources"); + assertThat(sourcesDirectory).exists(); + assertThat(collectRelativePaths(sourcesDirectory)).isNotEmpty(); + }); + } + + @TestTemplate + void whenTestAotRunsWithDevtoolsInClasspathItIsExcluded(MavenBuild mavenBuild) { + mavenBuild.project("aot-test-exclude-devtools").goals("process-test-classes").execute((project) -> { + Path aotDirectory = project.toPath().resolve("target/spring-aot/test"); + assertThat(aotDirectory).exists(); + Path sourcesDirectory = aotDirectory.resolve("sources"); + assertThat(sourcesDirectory).exists(); + assertThat(collectRelativePaths(sourcesDirectory)).isNotEmpty(); + }); + } + } diff --git a/build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-exclude-devtools/pom.xml b/build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-exclude-devtools/pom.xml new file mode 100644 index 00000000000..27c15bf381d --- /dev/null +++ b/build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-exclude-devtools/pom.xml @@ -0,0 +1,48 @@ + + + 4.0.0 + org.springframework.boot.maven.it + aot-exclude-devtools + 0.0.1.BUILD-SNAPSHOT + + UTF-8 + @java.version@ + @java.version@ + + + + + @project.groupId@ + @project.artifactId@ + @project.version@ + + + + process-aot + + + + + + + + + org.springframework.boot + spring-boot + @project.version@ + + + org.springframework.boot + spring-boot-devtools + @project.version@ + true + + + jakarta.servlet + jakarta.servlet-api + @jakarta-servlet.version@ + provided + + + diff --git a/build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-exclude-devtools/src/main/java/org/test/SampleApplication.java b/build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-exclude-devtools/src/main/java/org/test/SampleApplication.java new file mode 100644 index 00000000000..e26ea880dc7 --- /dev/null +++ b/build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-exclude-devtools/src/main/java/org/test/SampleApplication.java @@ -0,0 +1,29 @@ +/* + * 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 org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SampleApplication { + + public static void main(String[] args) { + SpringApplication.run(SampleApplication.class, args); + } + +} diff --git a/build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-test-exclude-devtools/pom.xml b/build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-test-exclude-devtools/pom.xml new file mode 100644 index 00000000000..69276c03b23 --- /dev/null +++ b/build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-test-exclude-devtools/pom.xml @@ -0,0 +1,60 @@ + + + 4.0.0 + org.springframework.boot.maven.it + aot-test-exclude-devtools + 0.0.1.BUILD-SNAPSHOT + + UTF-8 + @java.version@ + @java.version@ + + + + + @project.groupId@ + @project.artifactId@ + @project.version@ + + + + process-test-aot + + + + + + + + + org.springframework.boot + spring-boot + @project.version@ + + + org.springframework.boot + spring-boot-devtools + @project.version@ + true + + + org.springframework.boot + spring-boot-test + @project.version@ + test + + + org.junit.jupiter + junit-jupiter + @junit-jupiter.version@ + test + + + jakarta.servlet + jakarta.servlet-api + @jakarta-servlet.version@ + provided + + + diff --git a/build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-test-exclude-devtools/src/main/java/org/test/SampleApplication.java b/build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-test-exclude-devtools/src/main/java/org/test/SampleApplication.java new file mode 100644 index 00000000000..e26ea880dc7 --- /dev/null +++ b/build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-test-exclude-devtools/src/main/java/org/test/SampleApplication.java @@ -0,0 +1,29 @@ +/* + * 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 org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SampleApplication { + + public static void main(String[] args) { + SpringApplication.run(SampleApplication.class, args); + } + +} diff --git a/build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-test-exclude-devtools/src/test/java/org/test/SampleApplicationTests.java b/build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-test-exclude-devtools/src/test/java/org/test/SampleApplicationTests.java new file mode 100644 index 00000000000..973696313bf --- /dev/null +++ b/build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-test-exclude-devtools/src/test/java/org/test/SampleApplicationTests.java @@ -0,0 +1,29 @@ +/* + * 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 org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class SampleApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/ProcessAotMojo.java b/build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/ProcessAotMojo.java index 72d38f7815a..d5d13895ccd 100644 --- a/build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/ProcessAotMojo.java +++ b/build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/ProcessAotMojo.java @@ -130,7 +130,7 @@ public class ProcessAotMojo extends AbstractAotMojo { private URL[] getClassPath() throws Exception { File[] directories = new File[] { this.classesDirectory, this.generatedClasses }; - return getClassPath(directories, new ExcludeTestScopeArtifactFilter()); + return getClassPath(directories, new ExcludeTestScopeArtifactFilter(), DEVTOOLS_EXCLUDE_FILTER); } private RunArguments resolveArguments() { diff --git a/build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/ProcessTestAotMojo.java b/build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/ProcessTestAotMojo.java index a9806a617b8..b88e15ce77e 100644 --- a/build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/ProcessTestAotMojo.java +++ b/build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/ProcessTestAotMojo.java @@ -154,7 +154,7 @@ public class ProcessTestAotMojo extends AbstractAotMojo { protected URL[] getClassPath(boolean includeJUnitPlatformLauncher) throws Exception { File[] directories = new File[] { this.testClassesDirectory, this.generatedTestClasses, this.classesDirectory, this.generatedClasses }; - URL[] classPath = getClassPath(directories); + URL[] classPath = getClassPath(directories, DEVTOOLS_EXCLUDE_FILTER); if (!includeJUnitPlatformLauncher || this.project.getArtifactMap() .containsKey(JUNIT_PLATFORM_GROUP_ID + ":" + JUNIT_PLATFORM_LAUNCHER_ARTIFACT_ID)) { return classPath; diff --git a/starter/spring-boot-starter-parent/build.gradle b/starter/spring-boot-starter-parent/build.gradle index d3baf7914ac..e26b5028588 100644 --- a/starter/spring-boot-starter-parent/build.gradle +++ b/starter/spring-boot-starter-parent/build.gradle @@ -298,6 +298,12 @@ publishing.publications.withType(MavenPublication) { configuration { delegate.classesDirectory('${project.build.outputDirectory}') delegate.requiredVersion('22.3') + exclusions { + exclusion { + delegate.groupId('org.springframework.boot') + delegate.artifactId('spring-boot-devtools') + } + } } executions { execution { @@ -342,6 +348,12 @@ publishing.publications.withType(MavenPublication) { configuration { delegate.classesDirectory('${project.build.outputDirectory}') delegate.requiredVersion('22.3') + exclusions { + exclusion { + delegate.groupId('org.springframework.boot') + delegate.artifactId('spring-boot-devtools') + } + } } executions { execution {