You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by sl...@apache.org on 2026/10/13 21:31:48 UTC

(maven-dependency-plugin) 01/01: [MDEP-588] Add excludeOptional and excludeReactor to the dependency filter mojos

This is an automated email from the ASF dual-hosted git repository.

slachiewicz pushed a commit to branch agent/filter-optional-reactor
in repository https://gitbox.apache.org/repos/asf/maven-dependency-plugin.git

commit 9877601704cef5ce0d4f96e1e57147de96cf8a9b
Author: Sylwester Lachiewicz <sl...@apache.org>
AuthorDate: Tue Oct 13 23:11:12 2026 +0200

    [MDEP-588] Add excludeOptional and excludeReactor to the dependency filter mojos
---
 .../mdep-588-exclude-optional/invoker.properties   | 18 +++++
 src/it/projects/mdep-588-exclude-optional/pom.xml  | 75 +++++++++++++++++++++
 .../mdep-588-exclude-optional/verify.groovy        | 28 ++++++++
 .../mdep-589-exclude-reactor/child-a/pom.xml       | 31 +++++++++
 .../child-a/src/main/resources/DoNotDelete.xml     | 20 ++++++
 .../mdep-589-exclude-reactor/child-b/pom.xml       | 76 ++++++++++++++++++++++
 .../mdep-589-exclude-reactor/invoker.properties    | 18 +++++
 src/it/projects/mdep-589-exclude-reactor/pom.xml   | 36 ++++++++++
 .../mdep-589-exclude-reactor/verify.groovy         | 28 ++++++++
 .../AbstractDependencyFilterMojo.java              | 28 ++++++++
 .../filters/ExcludeOptionalArtifactsFilter.java    | 45 +++++++++++++
 .../examples/copying-project-dependencies.md.vm    | 68 +++++++++++++++++++
 .../fromDependencies/TestCopyDependenciesMojo.java | 52 +++++++++++++++
 13 files changed, 523 insertions(+)

diff --git a/src/it/projects/mdep-588-exclude-optional/invoker.properties b/src/it/projects/mdep-588-exclude-optional/invoker.properties
new file mode 100644
index 00000000..101be4e9
--- /dev/null
+++ b/src/it/projects/mdep-588-exclude-optional/invoker.properties
@@ -0,0 +1,18 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you 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
+#
+#   http://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.
+
+invoker.goals = clean process-sources
diff --git a/src/it/projects/mdep-588-exclude-optional/pom.xml b/src/it/projects/mdep-588-exclude-optional/pom.xml
new file mode 100644
index 00000000..3cf90844
--- /dev/null
+++ b/src/it/projects/mdep-588-exclude-optional/pom.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you 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
+  ~
+  ~   http://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.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.apache.maven.its.dependency</groupId>
+  <artifactId>mdep-588-exclude-optional</artifactId>
+  <version>1.0-SNAPSHOT</version>
+  <description>copy-dependencies with excludeOptional must skip optional dependencies (MDEP-588, MDEP-661).</description>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.maven.its.dependency</groupId>
+      <artifactId>ResourceArtifact</artifactId>
+      <version>1.0</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven.its.dependency</groupId>
+      <artifactId>ResourceArtifact</artifactId>
+      <version>1.0</version>
+      <classifier>client</classifier>
+      <optional>true</optional>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-dependency-plugin</artifactId>
+        <version>@project.version@</version>
+        <executions>
+          <execution>
+            <id>default</id>
+            <phase>process-sources</phase>
+            <goals>
+              <goal>copy-dependencies</goal>
+            </goals>
+            <configuration>
+              <outputDirectory>${project.build.directory}/default</outputDirectory>
+            </configuration>
+          </execution>
+          <execution>
+            <id>exclude-optional</id>
+            <phase>process-sources</phase>
+            <goals>
+              <goal>copy-dependencies</goal>
+            </goals>
+            <configuration>
+              <excludeOptional>true</excludeOptional>
+              <outputDirectory>${project.build.directory}/exclude-optional</outputDirectory>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/src/it/projects/mdep-588-exclude-optional/verify.groovy b/src/it/projects/mdep-588-exclude-optional/verify.groovy
new file mode 100644
index 00000000..c235a6d1
--- /dev/null
+++ b/src/it/projects/mdep-588-exclude-optional/verify.groovy
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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
+ *
+ *   http://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.
+ */
+
+File all = new File( basedir, 'target/default' )
+assert new File( all, 'ResourceArtifact-1.0.jar' ).isFile()
+assert new File( all, 'ResourceArtifact-1.0-client.jar' ).isFile()
+
+File withoutOptional = new File( basedir, 'target/exclude-optional' )
+assert new File( withoutOptional, 'ResourceArtifact-1.0.jar' ).isFile()
+assert !new File( withoutOptional, 'ResourceArtifact-1.0-client.jar' ).exists()
+
+return true
diff --git a/src/it/projects/mdep-589-exclude-reactor/child-a/pom.xml b/src/it/projects/mdep-589-exclude-reactor/child-a/pom.xml
new file mode 100644
index 00000000..39aa47fb
--- /dev/null
+++ b/src/it/projects/mdep-589-exclude-reactor/child-a/pom.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you 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
+  ~
+  ~   http://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.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.maven.its.dependency</groupId>
+    <artifactId>mdep-589-exclude-reactor</artifactId>
+    <version>1.0-SNAPSHOT</version>
+  </parent>
+  <artifactId>child-a</artifactId>
+</project>
diff --git a/src/it/projects/mdep-589-exclude-reactor/child-a/src/main/resources/DoNotDelete.xml b/src/it/projects/mdep-589-exclude-reactor/child-a/src/main/resources/DoNotDelete.xml
new file mode 100644
index 00000000..4d3d9e49
--- /dev/null
+++ b/src/it/projects/mdep-589-exclude-reactor/child-a/src/main/resources/DoNotDelete.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you 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
+  ~
+  ~   http://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.
+  -->
+<root/>
diff --git a/src/it/projects/mdep-589-exclude-reactor/child-b/pom.xml b/src/it/projects/mdep-589-exclude-reactor/child-b/pom.xml
new file mode 100644
index 00000000..4ec44553
--- /dev/null
+++ b/src/it/projects/mdep-589-exclude-reactor/child-b/pom.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you 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
+  ~
+  ~   http://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.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.maven.its.dependency</groupId>
+    <artifactId>mdep-589-exclude-reactor</artifactId>
+    <version>1.0-SNAPSHOT</version>
+  </parent>
+  <artifactId>child-b</artifactId>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.maven.its.dependency</groupId>
+      <artifactId>child-a</artifactId>
+      <version>1.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven.its.dependency</groupId>
+      <artifactId>ResourceArtifact</artifactId>
+      <version>1.0</version>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-dependency-plugin</artifactId>
+        <version>@project.version@</version>
+        <executions>
+          <execution>
+            <id>default</id>
+            <phase>package</phase>
+            <goals>
+              <goal>copy-dependencies</goal>
+            </goals>
+            <configuration>
+              <outputDirectory>${project.build.directory}/default</outputDirectory>
+            </configuration>
+          </execution>
+          <execution>
+            <id>exclude-reactor</id>
+            <phase>package</phase>
+            <goals>
+              <goal>copy-dependencies</goal>
+            </goals>
+            <configuration>
+              <excludeReactor>true</excludeReactor>
+              <outputDirectory>${project.build.directory}/exclude-reactor</outputDirectory>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/src/it/projects/mdep-589-exclude-reactor/invoker.properties b/src/it/projects/mdep-589-exclude-reactor/invoker.properties
new file mode 100644
index 00000000..a644cb7e
--- /dev/null
+++ b/src/it/projects/mdep-589-exclude-reactor/invoker.properties
@@ -0,0 +1,18 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you 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
+#
+#   http://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.
+
+invoker.goals = clean package
diff --git a/src/it/projects/mdep-589-exclude-reactor/pom.xml b/src/it/projects/mdep-589-exclude-reactor/pom.xml
new file mode 100644
index 00000000..b7f50efb
--- /dev/null
+++ b/src/it/projects/mdep-589-exclude-reactor/pom.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you 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
+  ~
+  ~   http://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.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <groupId>org.apache.maven.its.dependency</groupId>
+  <artifactId>mdep-589-exclude-reactor</artifactId>
+  <version>1.0-SNAPSHOT</version>
+  <packaging>pom</packaging>
+
+  <description>copy-dependencies with excludeReactor must skip dependencies that are reactor projects (MDEP-589).</description>
+
+  <modules>
+    <module>child-a</module>
+    <module>child-b</module>
+  </modules>
+</project>
diff --git a/src/it/projects/mdep-589-exclude-reactor/verify.groovy b/src/it/projects/mdep-589-exclude-reactor/verify.groovy
new file mode 100644
index 00000000..c6ccb98d
--- /dev/null
+++ b/src/it/projects/mdep-589-exclude-reactor/verify.groovy
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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
+ *
+ *   http://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.
+ */
+
+File all = new File( basedir, 'child-b/target/default' )
+assert new File( all, 'child-a-1.0-SNAPSHOT.jar' ).isFile()
+assert new File( all, 'ResourceArtifact-1.0.jar' ).isFile()
+
+File withoutReactor = new File( basedir, 'child-b/target/exclude-reactor' )
+assert !new File( withoutReactor, 'child-a-1.0-SNAPSHOT.jar' ).exists()
+assert new File( withoutReactor, 'ResourceArtifact-1.0.jar' ).isFile()
+
+return true
diff --git a/src/main/java/org/apache/maven/plugins/dependency/fromDependencies/AbstractDependencyFilterMojo.java b/src/main/java/org/apache/maven/plugins/dependency/fromDependencies/AbstractDependencyFilterMojo.java
index a483519a..8079e391 100644
--- a/src/main/java/org/apache/maven/plugins/dependency/fromDependencies/AbstractDependencyFilterMojo.java
+++ b/src/main/java/org/apache/maven/plugins/dependency/fromDependencies/AbstractDependencyFilterMojo.java
@@ -36,9 +36,11 @@ import org.apache.maven.model.Dependency;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugins.annotations.Parameter;
 import org.apache.maven.plugins.dependency.AbstractDependencyMojo;
+import org.apache.maven.plugins.dependency.resolvers.ExcludeReactorProjectsArtifactFilter;
 import org.apache.maven.plugins.dependency.utils.DependencyStatusSets;
 import org.apache.maven.plugins.dependency.utils.DependencyUtil;
 import org.apache.maven.plugins.dependency.utils.ResolverUtil;
+import org.apache.maven.plugins.dependency.utils.filters.ExcludeOptionalArtifactsFilter;
 import org.apache.maven.plugins.dependency.utils.translators.ArtifactTranslator;
 import org.apache.maven.plugins.dependency.utils.translators.ClassifierTypeTranslator;
 import org.apache.maven.project.DefaultProjectBuildingRequest;
@@ -101,6 +103,24 @@ public abstract class AbstractDependencyFilterMojo extends AbstractDependencyMoj
     @Parameter(property = "excludeTransitive", defaultValue = "false")
     protected boolean excludeTransitive;
 
+    /**
+     * If we should exclude optional dependencies, that is artifacts for which
+     * {@link Artifact#isOptional()} is {@code true}.
+     *
+     * @since 3.12.0
+     */
+    @Parameter(property = "excludeOptional", defaultValue = "false")
+    protected boolean excludeOptional;
+
+    /**
+     * If we should exclude artifacts that are projects of the current reactor build, matched by groupId,
+     * artifactId and version.
+     *
+     * @since 3.12.0
+     */
+    @Parameter(property = "excludeReactor", defaultValue = "false")
+    protected boolean excludeReactor;
+
     /**
      * Comma-separated list of Types to include. Empty String indicates include everything (default).
      *
@@ -339,6 +359,14 @@ public abstract class AbstractDependencyFilterMojo extends AbstractDependencyMoj
                 DependencyUtil.cleanToBeTokenizedString(this.includeArtifactIds),
                 DependencyUtil.cleanToBeTokenizedString(this.excludeArtifactIds)));
 
+        if (excludeOptional) {
+            filter.addFilter(new ExcludeOptionalArtifactsFilter());
+        }
+
+        if (excludeReactor) {
+            filter.addFilter(new ExcludeReactorProjectsArtifactFilter(session.getProjects(), getLog()));
+        }
+
         // start with all artifacts.
         Set<Artifact> artifacts;
 
diff --git a/src/main/java/org/apache/maven/plugins/dependency/utils/filters/ExcludeOptionalArtifactsFilter.java b/src/main/java/org/apache/maven/plugins/dependency/utils/filters/ExcludeOptionalArtifactsFilter.java
new file mode 100644
index 00000000..f19948db
--- /dev/null
+++ b/src/main/java/org/apache/maven/plugins/dependency/utils/filters/ExcludeOptionalArtifactsFilter.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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
+ *
+ *   http://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.apache.maven.plugins.dependency.utils.filters;
+
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.shared.artifact.filter.collection.AbstractArtifactsFilter;
+import org.apache.maven.shared.artifact.filter.collection.ArtifactFilterException;
+
+/**
+ * Filter that removes optional artifacts, that is artifacts for which {@link Artifact#isOptional()} is {@code true}.
+ *
+ * @since 3.12.0
+ */
+public class ExcludeOptionalArtifactsFilter extends AbstractArtifactsFilter {
+
+    @Override
+    public Set<Artifact> filter(Set<Artifact> artifacts) throws ArtifactFilterException {
+        Set<Artifact> result = new LinkedHashSet<>();
+        for (Artifact artifact : artifacts) {
+            if (!artifact.isOptional()) {
+                result.add(artifact);
+            }
+        }
+        return result;
+    }
+}
diff --git a/src/site/markdown/examples/copying-project-dependencies.md.vm b/src/site/markdown/examples/copying-project-dependencies.md.vm
index b82c99de..c9d75531 100644
--- a/src/site/markdown/examples/copying-project-dependencies.md.vm
+++ b/src/site/markdown/examples/copying-project-dependencies.md.vm
@@ -96,6 +96,74 @@ As mentioned, [transitive dependencies](https://maven.apache.org/guides/introduc
 </project>
 ```
 
+Excluding optional dependencies
+-------------------------------
+
+Dependencies declared with `<optional>true</optional>` are copied by default. Set the `excludeOptional` property to **true** to leave them out, for example when they are only needed to compile against and must not be shipped.
+
+```xml
+<project>
+  [...]
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-dependency-plugin</artifactId>
+        <version>${project.version}</version>
+        <executions>
+          <execution>
+            <id>copy-dependencies</id>
+            <phase>package</phase>
+            <goals>
+              <goal>copy-dependencies</goal>
+            </goals>
+            <configuration>
+              <outputDirectory>${esc.d}{project.build.directory}/alternateLocation</outputDirectory>
+              <excludeOptional>true</excludeOptional>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+  [...]
+</project>
+```
+
+Excluding reactor projects
+--------------------------
+
+When the project depends on artifacts that are themselves projects of the current reactor build, their jars are copied like any other dependency. Set the `excludeReactor` property to **true** to skip them, for example to build a class path that does not contain classes that are already in the reactor project's `target/classes`. Artifacts are matched to reactor projects by groupId, artifactId and version.
+
+```xml
+<project>
+  [...]
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-dependency-plugin</artifactId>
+        <version>${project.version}</version>
+        <executions>
+          <execution>
+            <id>copy-dependencies</id>
+            <phase>package</phase>
+            <goals>
+              <goal>copy-dependencies</goal>
+            </goals>
+            <configuration>
+              <outputDirectory>${esc.d}{project.build.directory}/alternateLocation</outputDirectory>
+              <excludeReactor>true</excludeReactor>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+  [...]
+</project>
+```
+
 Subtrees
 --------
 
diff --git a/src/test/java/org/apache/maven/plugins/dependency/fromDependencies/TestCopyDependenciesMojo.java b/src/test/java/org/apache/maven/plugins/dependency/fromDependencies/TestCopyDependenciesMojo.java
index 83715c63..4e239fe3 100644
--- a/src/test/java/org/apache/maven/plugins/dependency/fromDependencies/TestCopyDependenciesMojo.java
+++ b/src/test/java/org/apache/maven/plugins/dependency/fromDependencies/TestCopyDependenciesMojo.java
@@ -24,6 +24,7 @@ import java.io.File;
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.Set;
 
@@ -41,6 +42,7 @@ import org.apache.maven.plugins.dependency.utils.CopyUtil;
 import org.apache.maven.plugins.dependency.utils.DependencyUtil;
 import org.apache.maven.plugins.dependency.utils.markers.DefaultFileMarkerHandler;
 import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.util.FileUtils;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.io.TempDir;
@@ -51,7 +53,9 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.fail;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
 
 @MojoTest(realRepositorySession = true)
 class TestCopyDependenciesMojo {
@@ -437,6 +441,54 @@ class TestCopyDependenciesMojo {
         }
     }
 
+    @Test
+    @InjectMojo(goal = "copy-dependencies")
+    void testExcludeOptional(CopyDependenciesMojo mojo) throws Exception {
+        Set<Artifact> artifacts = stubFactory.getScopedArtifacts();
+        Artifact optional = artifacts.iterator().next();
+        optional.setOptional(true);
+        mojo.getProject().setArtifacts(artifacts);
+
+        // default keeps optional dependencies
+        mojo.execute();
+        assertTrue(new File(mojo.outputDirectory, DependencyUtil.getFormattedFileName(optional, false)).exists());
+        FileUtils.deleteDirectory(mojo.outputDirectory);
+
+        mojo.excludeOptional = true;
+        mojo.execute();
+
+        for (Artifact artifact : artifacts) {
+            File file = new File(mojo.outputDirectory, DependencyUtil.getFormattedFileName(artifact, false));
+            assertEquals(artifact != optional, file.exists(), artifact.getId());
+        }
+    }
+
+    @Test
+    @InjectMojo(goal = "copy-dependencies")
+    void testExcludeReactor(CopyDependenciesMojo mojo) throws Exception {
+        Set<Artifact> artifacts = stubFactory.getScopedArtifacts();
+        Artifact reactorArtifact = artifacts.iterator().next();
+        mojo.getProject().setArtifacts(artifacts);
+
+        MavenProject reactorProject = mock(MavenProject.class);
+        when(reactorProject.getArtifact()).thenReturn(reactorArtifact);
+        doReturn(Collections.singletonList(reactorProject)).when(session).getProjects();
+
+        // default keeps artifacts that are reactor projects
+        mojo.execute();
+        assertTrue(
+                new File(mojo.outputDirectory, DependencyUtil.getFormattedFileName(reactorArtifact, false)).exists());
+        FileUtils.deleteDirectory(mojo.outputDirectory);
+
+        mojo.excludeReactor = true;
+        mojo.execute();
+
+        for (Artifact artifact : artifacts) {
+            File file = new File(mojo.outputDirectory, DependencyUtil.getFormattedFileName(artifact, false));
+            assertEquals(artifact != reactorArtifact, file.exists(), artifact.getId());
+        }
+    }
+
     @Test
     @InjectMojo(goal = "copy-dependencies")
     void testSubPerType(CopyDependenciesMojo mojo) throws Exception {