From 58fc8f8c018da3d39a9ef7c9b9d65b226c1689ad Mon Sep 17 00:00:00 2001 From: Matti Tahvonen Date: Tue, 5 Mar 2024 20:01:31 +0200 Subject: [PATCH 1/3] Make excludes configurable via property See gh-39837 --- .../boot/maven/JarIntegrationTests.java | 17 ++++++++++++++++- .../maven/AbstractDependencyFilterMojo.java | 3 ++- .../org/springframework/boot/maven/Exclude.java | 15 +++++++++++++++ 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/JarIntegrationTests.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/JarIntegrationTests.java index e964c2ecee7..05b6879901f 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/JarIntegrationTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/JarIntegrationTests.java @@ -175,10 +175,25 @@ class JarIntegrationTests extends AbstractArchiveIntegrationTests { .hasEntryWithNameStartingWith("BOOT-INF/lib/spring-context") .hasEntryWithNameStartingWith("BOOT-INF/lib/spring-core") .hasEntryWithNameStartingWith("BOOT-INF/lib/spring-jcl") - .doesNotHaveEntryWithName("BOOT-INF/lib/servlet-api-2.5.jar"); + .doesNotHaveEntryWithNameStartingWith("BOOT-INF/lib/jakarta.servlet-api-"); }); } + @TestTemplate + void whenAnEntryIsExcludedWithPropertyItDoesNotAppearInTheRepackagedJar(MavenBuild mavenBuild) { + mavenBuild.project("jar") + .systemProperty("spring-boot.excludes", "jakarta.servlet:jakarta.servlet-api") + .goals("install") + .execute((project) -> { + File repackaged = new File(project, "target/jar-0.0.1.BUILD-SNAPSHOT.jar"); + assertThat(jar(repackaged)).hasEntryWithNameStartingWith("BOOT-INF/classes/") + .hasEntryWithNameStartingWith("BOOT-INF/lib/spring-context") + .hasEntryWithNameStartingWith("BOOT-INF/lib/spring-core") + .hasEntryWithNameStartingWith("BOOT-INF/lib/spring-jcl") + .doesNotHaveEntryWithNameStartingWith("BOOT-INF/lib/jakarta.servlet-api-"); + }); + } + @TestTemplate void whenAGroupIsExcludedNoEntriesInThatGroupAppearInTheRepackagedJar(MavenBuild mavenBuild) { mavenBuild.project("jar-exclude-group").goals("install").execute((project) -> { diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractDependencyFilterMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractDependencyFilterMojo.java index 0a665a04798..037b608a898 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractDependencyFilterMojo.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractDependencyFilterMojo.java @@ -82,7 +82,8 @@ public abstract class AbstractDependencyFilterMojo extends AbstractMojo { /** * Collection of artifact definitions to exclude. The {@link Exclude} element defines * mandatory {@code groupId} and {@code artifactId} properties and an optional - * {@code classifier} property. + * {@code classifier} property. If passing in excludes as a property the syntax is + *
-Dspring-boot.excludes=groupId1:artifactId1,groupId2:artifactId2:optional-qualifier
* @since 1.1.0 */ @Parameter(property = "spring-boot.excludes") diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/Exclude.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/Exclude.java index abacf74a351..9a795f11df5 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/Exclude.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/Exclude.java @@ -16,6 +16,8 @@ package org.springframework.boot.maven; +import org.springframework.util.Assert; + /** * A model for a dependency to exclude. * @@ -24,4 +26,17 @@ package org.springframework.boot.maven; */ public class Exclude extends FilterableDependency { + // Maven looks for this public method if giving excludes as property + // e.g. -Dspring-boot.excludes=myGroupId:myArtifactId:my-optional-classifier,foo:baz + public void set(String propertyInput) { + String[] parts = propertyInput.split(":"); + Assert.isTrue(parts.length == 2 || parts.length == 3, + "Exclude must be in the form groupId:artifactId:optional-classifier"); + setGroupId(parts[0]); + setArtifactId(parts[1]); + if (parts.length == 3) { + setClassifier(parts[2]); + } + } + } From 2a6293940b633f4d70d3ffa781b67d70dc53de0a Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Thu, 11 Apr 2024 16:28:32 +0100 Subject: [PATCH 2/3] Polish "Make excludes configurable via property" See gh-39837 --- .../springframework/boot/maven/JarIntegrationTests.java | 2 +- .../boot/maven/AbstractDependencyFilterMojo.java | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/JarIntegrationTests.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/JarIntegrationTests.java index 05b6879901f..72bc73f0bb6 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/JarIntegrationTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/JarIntegrationTests.java @@ -175,7 +175,7 @@ class JarIntegrationTests extends AbstractArchiveIntegrationTests { .hasEntryWithNameStartingWith("BOOT-INF/lib/spring-context") .hasEntryWithNameStartingWith("BOOT-INF/lib/spring-core") .hasEntryWithNameStartingWith("BOOT-INF/lib/spring-jcl") - .doesNotHaveEntryWithNameStartingWith("BOOT-INF/lib/jakarta.servlet-api-"); + .doesNotHaveEntryWithName("BOOT-INF/lib/servlet-api-2.5.jar"); }); } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractDependencyFilterMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractDependencyFilterMojo.java index 037b608a898..8b5409c6e7c 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractDependencyFilterMojo.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractDependencyFilterMojo.java @@ -81,9 +81,10 @@ public abstract class AbstractDependencyFilterMojo extends AbstractMojo { /** * Collection of artifact definitions to exclude. The {@link Exclude} element defines - * mandatory {@code groupId} and {@code artifactId} properties and an optional - * {@code classifier} property. If passing in excludes as a property the syntax is - *
-Dspring-boot.excludes=groupId1:artifactId1,groupId2:artifactId2:optional-qualifier
+ * mandatory {@code groupId} and {@code artifactId} components and an optional + * {@code classifier} component. When configured as a property, values should be + * comma-separated with colon-separated components: + * {@code groupId:artifactId,groupId:artifactId:classifier} * @since 1.1.0 */ @Parameter(property = "spring-boot.excludes") From baf5a7f13023d937a9d2bed973f297368a02a99d Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Thu, 11 Apr 2024 16:28:59 +0100 Subject: [PATCH 3/3] Make includes configurable via a property See gh-39837 --- .../boot/maven/JarIntegrationTests.java | 27 ++++++++++ .../projects/jar-include-entry/pom.xml | 50 +++++++++++++++++++ .../main/java/org/test/SampleApplication.java | 24 +++++++++ .../maven/AbstractDependencyFilterMojo.java | 9 ++-- .../springframework/boot/maven/Exclude.java | 17 +------ .../boot/maven/FilterableDependency.java | 23 ++++++++- 6 files changed, 128 insertions(+), 22 deletions(-) create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/jar-include-entry/pom.xml create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/jar-include-entry/src/main/java/org/test/SampleApplication.java diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/JarIntegrationTests.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/JarIntegrationTests.java index 72bc73f0bb6..31f6b520a52 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/JarIntegrationTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/JarIntegrationTests.java @@ -194,6 +194,33 @@ class JarIntegrationTests extends AbstractArchiveIntegrationTests { }); } + @TestTemplate + void whenAnEntryIsIncludedOnlyIncludedEntriesAppearInTheRepackagedJar(MavenBuild mavenBuild) { + mavenBuild.project("jar-include-entry").goals("install").execute((project) -> { + File repackaged = new File(project, "target/jar-include-entry-0.0.1.BUILD-SNAPSHOT.jar"); + assertThat(jar(repackaged)).hasEntryWithNameStartingWith("BOOT-INF/classes/") + .hasEntryWithNameStartingWith("BOOT-INF/lib/jakarta.servlet-api-") + .doesNotHaveEntryWithNameStartingWith("BOOT-INF/lib/spring-context") + .doesNotHaveEntryWithNameStartingWith("BOOT-INF/lib/spring-core") + .doesNotHaveEntryWithNameStartingWith("BOOT-INF/lib/spring-jcl"); + }); + } + + @TestTemplate + void whenAnIncludeIsSpecifiedAsAPropertyOnlyIncludedEntriesAppearInTheRepackagedJar(MavenBuild mavenBuild) { + mavenBuild.project("jar") + .systemProperty("spring-boot.includes", "jakarta.servlet:jakarta.servlet-api") + .goals("install") + .execute((project) -> { + File repackaged = new File(project, "target/jar-0.0.1.BUILD-SNAPSHOT.jar"); + assertThat(jar(repackaged)).hasEntryWithNameStartingWith("BOOT-INF/classes/") + .hasEntryWithNameStartingWith("BOOT-INF/lib/jakarta.servlet-api-") + .doesNotHaveEntryWithNameStartingWith("BOOT-INF/lib/spring-context") + .doesNotHaveEntryWithNameStartingWith("BOOT-INF/lib/spring-core") + .doesNotHaveEntryWithNameStartingWith("BOOT-INF/lib/spring-jcl"); + }); + } + @TestTemplate void whenAGroupIsExcludedNoEntriesInThatGroupAppearInTheRepackagedJar(MavenBuild mavenBuild) { mavenBuild.project("jar-exclude-group").goals("install").execute((project) -> { diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/jar-include-entry/pom.xml b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/jar-include-entry/pom.xml new file mode 100644 index 00000000000..9e4a5c10dfd --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/jar-include-entry/pom.xml @@ -0,0 +1,50 @@ + + + 4.0.0 + org.springframework.boot.maven.it + jar-include-entry + 0.0.1.BUILD-SNAPSHOT + + UTF-8 + @java.version@ + @java.version@ + + + + + @project.groupId@ + @project.artifactId@ + @project.version@ + + + + repackage + + + + + jakarta.servlet + jakarta.servlet-api + + + + + + + + + + + org.springframework + spring-context + @spring-framework.version@ + + + jakarta.servlet + jakarta.servlet-api + @jakarta-servlet.version@ + provided + + + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/jar-include-entry/src/main/java/org/test/SampleApplication.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/jar-include-entry/src/main/java/org/test/SampleApplication.java new file mode 100644 index 00000000000..1277cdbc5a6 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/jar-include-entry/src/main/java/org/test/SampleApplication.java @@ -0,0 +1,24 @@ +/* + * Copyright 2012-2024 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) { + } + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractDependencyFilterMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractDependencyFilterMojo.java index 8b5409c6e7c..63c0ff0fff3 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractDependencyFilterMojo.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractDependencyFilterMojo.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -71,9 +71,10 @@ public abstract class AbstractDependencyFilterMojo extends AbstractMojo { /** * Collection of artifact definitions to include. The {@link Include} element defines - * mandatory {@code groupId} and {@code artifactId} properties and an optional - * mandatory {@code groupId} and {@code artifactId} properties and an optional - * {@code classifier} property. + * mandatory {@code groupId} and {@code artifactId} components and an optional + * {@code classifier} component. When configured as a property, values should be + * comma-separated with colon-separated components: + * {@code groupId:artifactId,groupId:artifactId:classifier} * @since 1.2.0 */ @Parameter(property = "spring-boot.includes") diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/Exclude.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/Exclude.java index 9a795f11df5..23cf5e30deb 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/Exclude.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/Exclude.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2024 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. @@ -16,8 +16,6 @@ package org.springframework.boot.maven; -import org.springframework.util.Assert; - /** * A model for a dependency to exclude. * @@ -26,17 +24,4 @@ import org.springframework.util.Assert; */ public class Exclude extends FilterableDependency { - // Maven looks for this public method if giving excludes as property - // e.g. -Dspring-boot.excludes=myGroupId:myArtifactId:my-optional-classifier,foo:baz - public void set(String propertyInput) { - String[] parts = propertyInput.split(":"); - Assert.isTrue(parts.length == 2 || parts.length == 3, - "Exclude must be in the form groupId:artifactId:optional-classifier"); - setGroupId(parts[0]); - setArtifactId(parts[1]); - if (parts.length == 3) { - setClassifier(parts[2]); - } - } - } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/FilterableDependency.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/FilterableDependency.java index 2b4ead934f2..2d12921fa05 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/FilterableDependency.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/FilterableDependency.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2024 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. @@ -18,13 +18,16 @@ package org.springframework.boot.maven; import org.apache.maven.plugins.annotations.Parameter; +import org.springframework.util.Assert; + /** * A model for a dependency to include or exclude. * * @author Stephane Nicoll * @author David Turanski + * @since 3.1.11 */ -abstract class FilterableDependency { +public abstract class FilterableDependency { /** * The groupId of the artifact to exclude. @@ -68,4 +71,20 @@ abstract class FilterableDependency { this.classifier = classifier; } + /** + * Configures the include or exclude using a user-provided property in the form + * {@code groupId:artifactId} or {@code groupId:artifactId:classifier}. + * @param property the user-provided property + */ + public void set(String property) { + String[] parts = property.split(":"); + Assert.isTrue(parts.length == 2 || parts.length == 3, getClass().getSimpleName() + + " must be in the form groupId:artifactId or groupId:artifactId:classifier"); + setGroupId(parts[0]); + setArtifactId(parts[1]); + if (parts.length == 3) { + setClassifier(parts[2]); + } + } + }