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

Reply via email to