This is an automated email from the ASF dual-hosted git repository.
sjaranowski pushed a commit to branch maven-plugin-tools-3.x
in repository https://gitbox.apache.org/repos/asf/maven-plugin-tools.git
The following commit(s) were added to refs/heads/maven-plugin-tools-3.x by this
push:
new 5d1184f6 GH-944: Support root path exclusion for QDox scanning to
avoid existing blocking issues (#1046)
5d1184f6 is described below
commit 5d1184f66c1b05352c671d97e36a7c207a410eb7
Author: Ash <[email protected]>
AuthorDate: Fri Mar 6 21:07:58 2026 +0000
GH-944: Support root path exclusion for QDox scanning to avoid existing
blocking issues (#1046)
* GH-944: Allow users to specify root paths to exclude from QDox scanning
This enables users to work around issues such as
https://github.com/paul-hammant/qdox/issues/219,
https://github.com/paul-hammant/qdox/issues/1, etc that result in issues
such as https://github.com/apache/maven-plugin-tools/issues/944 being
raised.
With this change, users can specify a set of excluded scan directories that
source
trees reside within to prevent maven-plugin-plugin from feeding them into
the
Java source analysis tooling, which allows unblocking builds that are
completely
blocked until such a time that issues such as
https://github.com/paul-hammant/qdox/issues/287
are addressed. Given the long release span between releases of dependent
libraries,
developers will otherwise be blocked for long periods of time with
unbuildable
projects using the current tooling.
---
.../invoker.properties | 18 ++++
.../src/it/gh-944-exclude-source-directory/pom.xml | 108 +++++++++++++++++++++
.../org/apache/maven/plugin/coreit/FirstMojo.java | 52 ++++++++++
.../maven/plugin/coreit/SomeGeneratedModel.java | 34 +++++++
.../plugin/plugin/DescriptorGeneratorMojo.java | 34 +++++++
.../JavaAnnotationsMojoDescriptorExtractor.java | 17 +++-
.../tools/plugin/DefaultPluginToolsRequest.java | 31 ++++++
.../maven/tools/plugin/PluginToolsRequest.java | 29 ++++++
.../JavaJavadocMojoDescriptorExtractor.java | 8 +-
9 files changed, 326 insertions(+), 5 deletions(-)
diff --git
a/maven-plugin-plugin/src/it/gh-944-exclude-source-directory/invoker.properties
b/maven-plugin-plugin/src/it/gh-944-exclude-source-directory/invoker.properties
new file mode 100644
index 00000000..c959b536
--- /dev/null
+++
b/maven-plugin-plugin/src/it/gh-944-exclude-source-directory/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 = process-classes
diff --git a/maven-plugin-plugin/src/it/gh-944-exclude-source-directory/pom.xml
b/maven-plugin-plugin/src/it/gh-944-exclude-source-directory/pom.xml
new file mode 100644
index 00000000..2668f85d
--- /dev/null
+++ b/maven-plugin-plugin/src/it/gh-944-exclude-source-directory/pom.xml
@@ -0,0 +1,108 @@
+<?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.gh-944-exclude-source-directory</groupId>
+ <artifactId>gh-944-exclude-source-directory</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <packaging>maven-plugin</packaging>
+
+ <name>Maven Integration Test :: gh-944-exclude-source-directory</name>
+ <description>
+ Test plugin-plugin, plugin.xml descriptor - shouldn't contain explicitly
excluded source directories
+ </description>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-plugin-api</artifactId>
+ <version>@maven3Version@</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.maven.plugin-tools</groupId>
+ <artifactId>maven-plugin-annotations</artifactId>
+ <version>@project.version@</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <!-- Dependencies that are needed for the original bug reproduction -->
+ <dependency>
+ <groupId>org.immutables</groupId>
+ <artifactId>value</artifactId>
+ <version>2.12.0</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.jspecify</groupId>
+ <artifactId>jspecify</artifactId>
+ <version>1.0.0</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>@version.maven-compiler-plugin@</version>
+ <configuration>
+ <source>1.8</source>
+ <target>1.8</target>
+
+ <annotationProcessorPaths>
+ <path>
+ <groupId>org.immutables</groupId>
+ <artifactId>value</artifactId>
+ <version>2.12.0</version>
+ </path>
+ </annotationProcessorPaths>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-plugin-plugin</artifactId>
+ <version>@project.version@</version>
+ <configuration>
+ <excludedScanDirectories>
+ <!-- Example that is excluded to avoid
https://github.com/paul-hammant/qdox/issues/287 -->
+
<excludedScanDirectory>${project.build.directory}/generated-sources/annotations</excludedScanDirectory>
+ </excludedScanDirectories>
+ <goalPrefix>prefix</goalPrefix>
+ </configuration>
+ </plugin>
+ </plugins>
+
+ </build>
+</project>
diff --git
a/maven-plugin-plugin/src/it/gh-944-exclude-source-directory/src/main/java/org/apache/maven/plugin/coreit/FirstMojo.java
b/maven-plugin-plugin/src/it/gh-944-exclude-source-directory/src/main/java/org/apache/maven/plugin/coreit/FirstMojo.java
new file mode 100644
index 00000000..e459b61c
--- /dev/null
+++
b/maven-plugin-plugin/src/it/gh-944-exclude-source-directory/src/main/java/org/apache/maven/plugin/coreit/FirstMojo.java
@@ -0,0 +1,52 @@
+/*
+ * 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.plugin.coreit;
+
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.plugins.annotations.ResolutionScope;
+
+/**
+ * Touches a test file.
+ *
+ * @since 1.2
+ */
+@Mojo(
+ name = "first",
+ requiresDependencyResolution = ResolutionScope.TEST,
+ defaultPhase = LifecyclePhase.INTEGRATION_TEST)
+public class FirstMojo extends AbstractMojo {
+
+ /**
+ * @since 0.1
+ * @deprecated As of 0.2
+ */
+ @Parameter(alias = "alias")
+ private String aliasedParam;
+
+ @Parameter
+ private ModifiableSomeGeneratedModel foo;
+
+ public void execute() throws MojoExecutionException {
+ // nothing
+ }
+}
diff --git
a/maven-plugin-plugin/src/it/gh-944-exclude-source-directory/src/main/java/org/apache/maven/plugin/coreit/SomeGeneratedModel.java
b/maven-plugin-plugin/src/it/gh-944-exclude-source-directory/src/main/java/org/apache/maven/plugin/coreit/SomeGeneratedModel.java
new file mode 100644
index 00000000..c5290edd
--- /dev/null
+++
b/maven-plugin-plugin/src/it/gh-944-exclude-source-directory/src/main/java/org/apache/maven/plugin/coreit/SomeGeneratedModel.java
@@ -0,0 +1,34 @@
+/*
+ * 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.plugin.coreit;
+
+import java.util.List;
+
+import org.immutables.value.Value.Immutable;
+import org.immutables.value.Value.Modifiable;
+import org.jspecify.annotations.Nullable;
+
+@Immutable
+@Modifiable
+public interface SomeGeneratedModel {
+ // Triggers https://github.com/paul-hammant/qdox/issues/287 on the
generated code when QDox tries
+ // to scan it.
+ @Nullable
+ List<@Nullable String> getThings();
+}
diff --git
a/maven-plugin-plugin/src/main/java/org/apache/maven/plugin/plugin/DescriptorGeneratorMojo.java
b/maven-plugin-plugin/src/main/java/org/apache/maven/plugin/plugin/DescriptorGeneratorMojo.java
index ffbb3644..11d70758 100644
---
a/maven-plugin-plugin/src/main/java/org/apache/maven/plugin/plugin/DescriptorGeneratorMojo.java
+++
b/maven-plugin-plugin/src/main/java/org/apache/maven/plugin/plugin/DescriptorGeneratorMojo.java
@@ -130,6 +130,39 @@ public class DescriptorGeneratorMojo extends
AbstractGeneratorMojo {
@Parameter
private Set<String> extractors;
+ /**
+ * A set of root directories to exclude from being scanned, if the
extractor scans source directories
+ * to obtain metadata.
+ *
+ * <p>Globs are also supported here.
+ *
+ * <p>Users can specify this to prevent certain generated source roots
from being parsed by this plugin
+ * in the event that those source roots contain potentially malformed or
incompatible code.
+ *
+ * <p>This is primarily designed to facilitate allowing this plugin to
operate with generated sources
+ * that use annotations or documentation in an uncontrollable format that
may conflict with the parsing
+ * rules we utilise.
+ *
+ * <p>Note that this only accepts <strong>source roots</strong>. It will
not accept
+ * specific paths within a source root (e.g. specific packages). In this
context, a source root
+ * would be considered to be a directory holding a full Java package
structure which can be
+ * passed directly to {@code javac} for compilation, or {@code javadoc}
for documentation.
+ *
+ * <p>As an example, the following configuration will prevent this goal
scanning any
+ * generated sources from annotation processors:
+ *
+ * <pre>{@code
+ * <excludedScanDirectories>
+ *
<excludedScanDirectory>${project.build.directory}/generated-sources/annotations</excludedScanDirectory>
+ *
<excludedScanDirectory>${project.build.directory}/generated-test-sources/annotations</excludedScanDirectory>
+ * </excludedScanDirectories>
+ * }</pre>
+ *
+ * @since TBC
+ */
+ @Parameter
+ private Set<String> excludedScanDirectories = Collections.emptySet();
+
/**
* By default, an exception is throw if no mojo descriptor is found. As
the maven-plugin is defined in core, the
* descriptor generator mojo is bound to generate-resources phase.
@@ -351,6 +384,7 @@ public class DescriptorGeneratorMojo extends
AbstractGeneratorMojo {
request.setInternalJavadocVersion(internalJavadocVersion);
request.setExternalJavadocBaseUrls(externalJavadocBaseUrls);
request.setSettings(mavenSession.getSettings());
+ request.setExcludedScanDirectories(excludedScanDirectories);
mojoScanner.populatePluginDescriptor(request);
request.setPluginDescriptor(extendPluginDescriptor(request));
diff --git
a/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/JavaAnnotationsMojoDescriptorExtractor.java
b/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/JavaAnnotationsMojoDescriptorExtractor.java
index 04347349..b44f3c37 100644
---
a/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/JavaAnnotationsMojoDescriptorExtractor.java
+++
b/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/JavaAnnotationsMojoDescriptorExtractor.java
@@ -254,7 +254,7 @@ public class JavaAnnotationsMojoDescriptorExtractor
implements MojoDescriptorExt
JavaProjectBuilder builder = new JavaProjectBuilder(new
SortedClassLibraryBuilder());
builder.setEncoding(request.getEncoding());
- extendJavaProjectBuilder(builder, request.getProject());
+ extendJavaProjectBuilder(request, builder, request.getProject());
for (MojoAnnotatedClass mojoAnnotatedClass : mojoAnnotatedClasses) {
if (Objects.equals(
@@ -289,7 +289,7 @@ public class JavaAnnotationsMojoDescriptorExtractor
implements MojoDescriptorExt
}
for (MavenProject mavenProject : mavenProjects) {
- extendJavaProjectBuilder(builder, mavenProject);
+ extendJavaProjectBuilder(request, builder, mavenProject);
}
return builder;
@@ -630,11 +630,19 @@ public class JavaAnnotationsMojoDescriptorExtractor
implements MojoDescriptorExt
}
}
- private void extendJavaProjectBuilder(JavaProjectBuilder builder, final
MavenProject project) {
+ private void extendJavaProjectBuilder(
+ PluginToolsRequest request, JavaProjectBuilder builder, final
MavenProject project) {
List<File> sources = new ArrayList<>();
for (String source : project.getCompileSourceRoots()) {
- sources.add(new File(source));
+ File sourceFile = new File(source);
+
+ // Allow users to exclude certain paths such as generated sources
from being scanned, in the case that
+ // this may be problematic for them (e.g. using obscure
unsupported syntax by the parser, comments that
+ // cannot be controlled, etc.)
+ if (!request.isExcludedScanDirectory(sourceFile)) {
+ sources.add(sourceFile);
+ }
}
// TODO be more dynamic
@@ -642,6 +650,7 @@ public class JavaAnnotationsMojoDescriptorExtractor
implements MojoDescriptorExt
if
(!project.getCompileSourceRoots().contains(generatedPlugin.getAbsolutePath())
&& generatedPlugin.exists()) {
sources.add(generatedPlugin);
}
+
extendJavaProjectBuilder(builder, sources, project.getArtifacts());
}
diff --git
a/maven-plugin-tools-api/src/main/java/org/apache/maven/tools/plugin/DefaultPluginToolsRequest.java
b/maven-plugin-tools-api/src/main/java/org/apache/maven/tools/plugin/DefaultPluginToolsRequest.java
index 1beb5379..e1009aa9 100644
---
a/maven-plugin-tools-api/src/main/java/org/apache/maven/tools/plugin/DefaultPluginToolsRequest.java
+++
b/maven-plugin-tools-api/src/main/java/org/apache/maven/tools/plugin/DefaultPluginToolsRequest.java
@@ -18,7 +18,11 @@
*/
package org.apache.maven.tools.plugin;
+import java.io.File;
import java.net.URI;
+import java.nio.file.FileSystem;
+import java.nio.file.Path;
+import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -66,6 +70,8 @@ public class DefaultPluginToolsRequest implements
PluginToolsRequest {
private String mavenApiVersion;
+ private Collection<String> excludedScanDirectories;
+
public DefaultPluginToolsRequest(MavenProject project, PluginDescriptor
pluginDescriptor) {
this.project = project;
this.pluginDescriptor = pluginDescriptor;
@@ -232,4 +238,29 @@ public class DefaultPluginToolsRequest implements
PluginToolsRequest {
public String getUsedMavenApiVersion() {
return mavenApiVersion;
}
+
+ @Override
+ public Collection<String> getExcludedScanDirectories() {
+ if (excludedScanDirectories == null) {
+ excludedScanDirectories = new HashSet<>();
+ }
+ return excludedScanDirectories;
+ }
+
+ @Override
+ public void setExcludedScanDirectories(Collection<String>
excludedScanDirectories) {
+ this.excludedScanDirectories = excludedScanDirectories;
+ }
+
+ @Override
+ public boolean isExcludedScanDirectory(File sourceFile) {
+ Path sourcePath = sourceFile.toPath();
+ FileSystem sourceFs = sourcePath.getFileSystem();
+ for (String excludedScanDirectory : getExcludedScanDirectories()) {
+ if (sourceFs.getPathMatcher("glob:" +
excludedScanDirectory).matches(sourcePath)) {
+ return true;
+ }
+ }
+ return false;
+ }
}
diff --git
a/maven-plugin-tools-api/src/main/java/org/apache/maven/tools/plugin/PluginToolsRequest.java
b/maven-plugin-tools-api/src/main/java/org/apache/maven/tools/plugin/PluginToolsRequest.java
index 079b120d..b1e85710 100644
---
a/maven-plugin-tools-api/src/main/java/org/apache/maven/tools/plugin/PluginToolsRequest.java
+++
b/maven-plugin-tools-api/src/main/java/org/apache/maven/tools/plugin/PluginToolsRequest.java
@@ -18,7 +18,9 @@
*/
package org.apache.maven.tools.plugin;
+import java.io.File;
import java.net.URI;
+import java.util.Collection;
import java.util.List;
import java.util.Set;
@@ -211,4 +213,31 @@ public interface PluginToolsRequest {
* @since 3.8.0
*/
String getUsedMavenApiVersion();
+
+ /**
+ * Get the collection of directories to exclude from scanning during the
detection of sources.
+ *
+ * <p>Treated as globs internally.
+ *
+ * @return the directories to exclude from scanning during detection of
sources.
+ * @since TBC
+ */
+ Collection<String> getExcludedScanDirectories();
+
+ /**
+ * Set the collection of directories to exclude from scanning during the
detection of sources.
+ *
+ * @param excludedScanDirectories the directories to exclude from scanning
during detection of sources.
+ * @since TBC
+ */
+ void setExcludedScanDirectories(Collection<String>
excludedScanDirectories);
+
+ /**
+ * Determine if the given scan directory should be excluded.
+ *
+ * @param sourceFile the source file to check.
+ * @return true if excluded, false otherwise.
+ * @since TBC
+ */
+ boolean isExcludedScanDirectory(File sourceFile);
}
diff --git
a/maven-plugin-tools-java/src/main/java/org/apache/maven/tools/plugin/extractor/javadoc/JavaJavadocMojoDescriptorExtractor.java
b/maven-plugin-tools-java/src/main/java/org/apache/maven/tools/plugin/extractor/javadoc/JavaJavadocMojoDescriptorExtractor.java
index 7bd772f6..60ad5dff 100644
---
a/maven-plugin-tools-java/src/main/java/org/apache/maven/tools/plugin/extractor/javadoc/JavaJavadocMojoDescriptorExtractor.java
+++
b/maven-plugin-tools-java/src/main/java/org/apache/maven/tools/plugin/extractor/javadoc/JavaJavadocMojoDescriptorExtractor.java
@@ -548,7 +548,13 @@ public class JavaJavadocMojoDescriptorExtractor implements
MojoDescriptorExtract
MavenProject project = request.getProject();
for (String source : project.getCompileSourceRoots()) {
- builder.addSourceTree(new File(source));
+ // Allow users to exclude certain paths such as generated sources
from being scanned, in the case that
+ // this may be problematic for them (e.g. using obscure
unsupported syntax by the parser, comments that
+ // cannot be controlled, etc.)
+ File sourceFile = new File(source);
+ if (!request.isExcludedScanDirectory(sourceFile)) {
+ builder.addSourceTree(sourceFile);
+ }
}
// TODO be more dynamic