diff --git a/api/maven-api-model/src/main/mdo/maven.mdo b/api/maven-api-model/src/main/mdo/maven.mdo
index 550da862be..1cf8f2ea49 100644
--- a/api/maven-api-model/src/main/mdo/maven.mdo
+++ b/api/maven-api-model/src/main/mdo/maven.mdo
@@ -1366,6 +1366,9 @@
} element contains informations required to exclude
an artifact to the project.
+
+ The {@code groupId} and {@code artifactId} fields are interpreted as glob patterns,
+ see {@link java.nio.file.FileSystem#getPathMatcher}.
]]>
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/resolver/filter/ExclusionArtifactFilter.java b/maven-core/src/main/java/org/apache/maven/artifact/resolver/filter/ExclusionArtifactFilter.java
index c2d3ae1599..1defc48556 100644
--- a/maven-core/src/main/java/org/apache/maven/artifact/resolver/filter/ExclusionArtifactFilter.java
+++ b/maven-core/src/main/java/org/apache/maven/artifact/resolver/filter/ExclusionArtifactFilter.java
@@ -18,8 +18,13 @@
*/
package org.apache.maven.artifact.resolver.filter;
+import java.lang.reflect.Proxy;
+import java.nio.file.FileSystems;
+import java.nio.file.Path;
+import java.nio.file.PathMatcher;
import java.util.List;
import java.util.function.Predicate;
+import java.util.stream.Collectors;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.model.Exclusion;
@@ -28,37 +33,42 @@ import org.apache.maven.model.Exclusion;
* Filter to exclude from a list of artifact patterns.
*/
public class ExclusionArtifactFilter implements ArtifactFilter {
- private static final String WILDCARD = "*";
private final List exclusions;
+ private final List> predicates;
public ExclusionArtifactFilter(List exclusions) {
this.exclusions = exclusions;
- }
-
- private Predicate sameArtifactId(Artifact artifact) {
- return exclusion -> exclusion.getArtifactId().equals(artifact.getArtifactId());
- }
-
- private Predicate sameGroupId(Artifact artifact) {
- return exclusion -> exclusion.getGroupId().equals(artifact.getGroupId());
- }
-
- private Predicate groupIdIsWildcard = exclusion -> WILDCARD.equals(exclusion.getGroupId());
-
- private Predicate artifactIdIsWildcard = exclusion -> WILDCARD.equals(exclusion.getArtifactId());
-
- private Predicate groupIdAndArtifactIdIsWildcard = groupIdIsWildcard.and(artifactIdIsWildcard);
-
- private Predicate exclude(Artifact artifact) {
- return groupIdAndArtifactIdIsWildcard
- .or(groupIdIsWildcard.and(sameArtifactId(artifact)))
- .or(artifactIdIsWildcard.and(sameGroupId(artifact)))
- .or(sameGroupId(artifact).and(sameArtifactId(artifact)));
+ this.predicates =
+ exclusions.stream().map(ExclusionArtifactFilter::toPredicate).collect(Collectors.toList());
}
@Override
public boolean include(Artifact artifact) {
- return !exclusions.stream().anyMatch(exclude(artifact));
+ return predicates.stream().noneMatch(p -> p.test(artifact));
+ }
+
+ private static Predicate toPredicate(Exclusion exclusion) {
+ PathMatcher groupId = FileSystems.getDefault().getPathMatcher("glob:" + exclusion.getGroupId());
+ PathMatcher artifactId = FileSystems.getDefault().getPathMatcher("glob:" + exclusion.getArtifactId());
+ Predicate predGroupId = a -> groupId.matches(createPathProxy(a.getGroupId()));
+ Predicate predArtifactId = a -> artifactId.matches(createPathProxy(a.getArtifactId()));
+ return predGroupId.and(predArtifactId);
+ }
+
+ /**
+ * In order to reuse the glob matcher from the filesystem, we need
+ * to create Path instances. Those are only used with the toString method.
+ * This hack works because the only system-dependent thing is the path
+ * separator which should not be part of the groupId or artifactId.
+ */
+ private static Path createPathProxy(String value) {
+ return (Path) Proxy.newProxyInstance(
+ ExclusionArtifactFilter.class.getClassLoader(), new Class[] {Path.class}, (proxy1, method, args) -> {
+ if ("toString".equals(method.getName())) {
+ return value;
+ }
+ throw new UnsupportedOperationException();
+ });
}
}
diff --git a/maven-core/src/test/java/org/apache/maven/artifact/resolver/filter/ExclusionArtifactFilterTest.java b/maven-core/src/test/java/org/apache/maven/artifact/resolver/filter/ExclusionArtifactFilterTest.java
index bcb5bf1f83..4347e1a8dc 100644
--- a/maven-core/src/test/java/org/apache/maven/artifact/resolver/filter/ExclusionArtifactFilterTest.java
+++ b/maven-core/src/test/java/org/apache/maven/artifact/resolver/filter/ExclusionArtifactFilterTest.java
@@ -33,12 +33,17 @@ import static org.mockito.Mockito.when;
class ExclusionArtifactFilterTest {
private Artifact artifact;
+ private Artifact artifact2;
@BeforeEach
void setup() {
artifact = mock(Artifact.class);
when(artifact.getGroupId()).thenReturn("org.apache.maven");
when(artifact.getArtifactId()).thenReturn("maven-core");
+
+ artifact2 = mock(Artifact.class);
+ when(artifact2.getGroupId()).thenReturn("org.junit.jupiter");
+ when(artifact2.getArtifactId()).thenReturn("junit-jupiter-engine");
}
@Test
@@ -140,4 +145,26 @@ class ExclusionArtifactFilterTest {
assertThat(filter.include(artifact), is(false));
}
+
+ @Test
+ void testExcludeWithGlob() {
+ Exclusion exclusion = new Exclusion();
+ exclusion.setGroupId("*");
+ exclusion.setArtifactId("maven-*");
+ ExclusionArtifactFilter filter = new ExclusionArtifactFilter(Collections.singletonList(exclusion));
+
+ assertThat(filter.include(artifact), is(false));
+ assertThat(filter.include(artifact2), is(true));
+ }
+
+ @Test
+ void testExcludeWithGlobStar() {
+ Exclusion exclusion = new Exclusion();
+ exclusion.setGroupId("**");
+ exclusion.setArtifactId("maven-**");
+ ExclusionArtifactFilter filter = new ExclusionArtifactFilter(Collections.singletonList(exclusion));
+
+ assertThat(filter.include(artifact), is(false));
+ assertThat(filter.include(artifact2), is(true));
+ }
}