-
Couldn't load subscription status.
- Fork 103
Fix excludePackageNames wildcard handling to correctly match subpackages #1275
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Fixes excludePackageNames wildcard handling so trailing wildcards match all nested subpackages, aligning behavior with javadoc’s -exclude semantics for recursive exclusion.
- Update regex generation to treat leading and trailing wildcards as recursive (.+) and middle wildcards as single-segment ([^sep]+)
- Clarify plugin Javadoc to document wildcard behavior with concrete examples
- Add tests covering recursive and single-segment wildcard scenarios
Reviewed Changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| src/main/java/org/apache/maven/plugins/javadoc/JavadocUtil.java | Adjust wildcard-to-regex conversion to correctly handle trailing wildcards as recursive. |
| src/main/java/org/apache/maven/plugins/javadoc/AbstractJavadocMojo.java | Update documentation and examples to reflect new wildcard behavior. |
| src/test/java/org/apache/maven/plugins/javadoc/JavadocUtilTest.java | Add tests validating recursive and single-level wildcard matching across various patterns. |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| // Following implementation should match requirements as aligned with javadoc -exclude behavior: | ||
| // - A wildcard at the beginning should match one or more directories | ||
| // - Any other wildcard must match exactly one directory | ||
| Pattern p = Pattern.compile(excludePackagename | ||
| .replace(".", regexFileSeparator) | ||
| .replaceFirst("^\\*", ".+") | ||
| .replace("*", "[^" + regexFileSeparator + "]+")); | ||
| // - A wildcard at the end should match one or more directories (to include all subpackages) | ||
| // - A wildcard in the middle should match exactly one directory |
Copilot
AI
Oct 15, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment suggests full alignment with javadoc -exclude behavior, but the plugin’s documented behavior (and tests) keep bare package names (e.g., org.acme.exclude2) as exact-only (not recursive). Please rephrase to clarify this only aligns trailing wildcards with javadoc, not bare package names.
| String pattern = excludePackagename.replace(".", regexFileSeparator); | ||
| // Handle leading wildcard: match one or more directory levels | ||
| pattern = pattern.replaceFirst("^\\*", ".+"); | ||
| // Handle trailing wildcard: match one or more directory levels (for subpackages) | ||
| pattern = pattern.replaceFirst("\\*$", ".+"); | ||
| // Handle wildcards in the middle: match exactly one directory level | ||
| pattern = pattern.replace("*", "[^" + regexFileSeparator + "]+"); |
Copilot
AI
Oct 15, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] To avoid unintended regex interpretation of literal characters, build the regex by quoting non-wildcard fragments and inserting the appropriate wildcard expansions based on position. This keeps behavior the same while making the transformation robust against any non-package characters.
| String pattern = excludePackagename.replace(".", regexFileSeparator); | |
| // Handle leading wildcard: match one or more directory levels | |
| pattern = pattern.replaceFirst("^\\*", ".+"); | |
| // Handle trailing wildcard: match one or more directory levels (for subpackages) | |
| pattern = pattern.replaceFirst("\\*$", ".+"); | |
| // Handle wildcards in the middle: match exactly one directory level | |
| pattern = pattern.replace("*", "[^" + regexFileSeparator + "]+"); | |
| // Build regex by quoting non-wildcard fragments and inserting wildcard expansions | |
| StringBuilder patternBuilder = new StringBuilder(); | |
| String[] parts = excludePackagename.split("\\*", -1); // -1 to include trailing empty strings | |
| for (int i = 0; i < parts.length; i++) { | |
| if (!parts[i].isEmpty()) { | |
| // Replace '.' with file separator and quote the fragment | |
| patternBuilder.append(Pattern.quote(parts[i].replace(".", regexFileSeparator))); | |
| } | |
| if (i < parts.length - 1) { | |
| // Insert wildcard regex | |
| // If at start or end, use ".+" (one or more directories), else "[^sep]+" | |
| boolean isStart = (i == 0); | |
| boolean isEnd = (i == parts.length - 2 && parts[parts.length - 1].isEmpty()); | |
| if (isStart || isEnd) { | |
| patternBuilder.append(".+"); | |
| } else { | |
| patternBuilder.append("[^").append(regexFileSeparator).append("]+"); | |
| } | |
| } | |
| } | |
| String pattern = patternBuilder.toString(); |
Problem
The
excludePackageNamesparameter with trailing wildcard patterns likeorg.example.*was only matching direct subpackages (one level deep), but not nested subpackages. This caused builds to fail when using wildcards to exclude package hierarchies, particularly noticeable with Java 25.For example, with
<excludePackageNames>org.example.*</excludePackageNames>:org.example.sub1,org.example.sub2org.example.sub2.subsub,org.example.sub1.deep.nestedThis was inconsistent with the javadoc
-excludeoption behavior, which according to Oracle's documentation "unconditionally excludes the specified packages and their subpackages."Root Cause
The regex pattern conversion in
JavadocUtil.getExcludedPackages()was treating all non-leading wildcards the same way, converting*to[^/]+which matches exactly one directory level. This meant:org.example.*→org/example/[^/]+(matches only one level)org.example.*→org/example/.+(matches one or more levels)Solution
Updated the wildcard-to-regex conversion logic to distinguish between:
*.internal) →.+- matches one or more package segmentsorg.example.*) →.+- matches one or more package segments (all subpackages)org.*.sub1) →[^/]+- matches exactly one package segmentThis ensures trailing wildcards correctly exclude all subpackages at any depth, aligning with javadoc's
-excludeoption behavior.Changes
.+instead of[^/]+Example
With this fix,
<excludePackageNames>org.example.*</excludePackageNames>now correctly excludes:org.example.sub1org.example.sub2org.example.sub2.subsub✨ (previously missed)org.example.sub1.deep.nested✨ (previously missed)Fixes issue where excludePackageNames with wildcards stopped working correctly in recent Java versions.