5959 * If above changes are not desired, put an explicit {@code "glob:"} prefix before the pattern.
6060 * Note that putting such a prefix is recommended anyway for better performances.
6161 *
62- * @author Benjamin Bentmann
63- * @author Martin Desruisseaux
64- *
6562 * @see java.nio.file.FileSystem#getPathMatcher(String)
6663 */
6764public class PathSelector implements PathMatcher {
@@ -171,14 +168,16 @@ public class PathSelector implements PathMatcher {
171168 /**
172169 * String representations of the normalized include filters.
173170 * Each pattern shall be prefixed by its syntax, which is {@value #DEFAULT_SYNTAX} by default.
171+ * An empty array means to include all files.
174172 *
175173 * @see #toString()
176174 */
177175 private final String [] includePatterns ;
178176
179177 /**
180178 * String representations of the normalized exclude filters.
181- * Each pattern shall be prefixed by its syntax, which is {@value #DEFAULT_SYNTAX} by default.
179+ * Each pattern shall be prefixed by its syntax. If no syntax is specified,
180+ * the default is a Maven 3 syntax similar, but not identical, to {@value #DEFAULT_SYNTAX}.
182181 * This array may be longer or shorter than the user-supplied excludes, depending on whether
183182 * default excludes have been added and whether some unnecessary excludes have been omitted.
184183 *
@@ -188,6 +187,7 @@ public class PathSelector implements PathMatcher {
188187
189188 /**
190189 * The matcher for includes. The length of this array is equal to {@link #includePatterns} array length.
190+ * An empty array means to include all files.
191191 */
192192 private final PathMatcher [] includes ;
193193
@@ -200,6 +200,7 @@ public class PathSelector implements PathMatcher {
200200 * The matcher for all directories to include. This array includes the parents of all those directories,
201201 * because they need to be accepted before we can walk to the sub-directories.
202202 * This is an optimization for skipping whole directories when possible.
203+ * An empty array means to include all directories.
203204 */
204205 private final PathMatcher [] dirIncludes ;
205206
@@ -215,6 +216,13 @@ public class PathSelector implements PathMatcher {
215216 */
216217 private final Path baseDirectory ;
217218
219+ /**
220+ * Whether paths must be relativized before being given to a matcher. If {@code true}, then every paths
221+ * will be made relative to {@link #baseDirectory} for allowing patterns like {@code "foo/bar/*.java"}
222+ * to work. As a slight optimization, we can skip this step if all patterns start with {@code "**"}.
223+ */
224+ private final boolean needRelativize ;
225+
218226 /**
219227 * Creates a new selector from the given includes and excludes.
220228 *
@@ -232,17 +240,18 @@ public PathSelector(
232240 baseDirectory = Objects .requireNonNull (directory , "directory cannot be null" );
233241 includePatterns = normalizePatterns (includes , false );
234242 excludePatterns = normalizePatterns (effectiveExcludes (excludes , includePatterns , useDefaultExcludes ), true );
235- FileSystem system = baseDirectory .getFileSystem ();
236- this .includes = matchers (system , includePatterns );
237- this .excludes = matchers (system , excludePatterns );
238- dirIncludes = matchers (system , directoryPatterns (includePatterns , false ));
239- dirExcludes = matchers (system , directoryPatterns (excludePatterns , true ));
243+ FileSystem fileSystem = baseDirectory .getFileSystem ();
244+ this .includes = matchers (fileSystem , includePatterns );
245+ this .excludes = matchers (fileSystem , excludePatterns );
246+ dirIncludes = matchers (fileSystem , directoryPatterns (includePatterns , false ));
247+ dirExcludes = matchers (fileSystem , directoryPatterns (excludePatterns , true ));
248+ needRelativize = needRelativize (includePatterns ) || needRelativize (excludePatterns );
240249 }
241250
242251 /**
243252 * Returns the given array of excludes, optionally expanded with a default set of excludes,
244253 * then with unnecessary excludes omitted. An unnecessary exclude is an exclude which will never
245- * match a file because there is no include which would accept a file that could match the exclude.
254+ * match a file because there are no includes which would accept a file that could match the exclude.
246255 * For example, if the only include is {@code "*.java"}, then the <code>"**/project.pj"</code>,
247256 * <code>"**/.DS_Store"</code> and other excludes will never match a file and can be omitted.
248257 * Because the list of {@linkplain #DEFAULT_EXCLUDES default excludes} contains many elements,
@@ -269,10 +278,14 @@ private static Collection<String> effectiveExcludes(
269278 }
270279 } else {
271280 excludes = new ArrayList <>(excludes );
281+ excludes .removeIf (Objects ::isNull );
272282 if (useDefaultExcludes ) {
273283 excludes .addAll (DEFAULT_EXCLUDES );
274284 }
275285 }
286+ if (includes .length == 0 ) {
287+ return excludes ;
288+ }
276289 /*
277290 * Get the prefixes and suffixes of all includes, stopping at the first special character.
278291 * Redundant prefixes and suffixes are omitted.
@@ -473,7 +486,7 @@ private static void addPatternsWithOneDirRemoved(final Set<String> patterns, fin
473486 * Applies some heuristic rules for simplifying the set of patterns,
474487 * then returns the patterns as an array.
475488 *
476- * @param patterns the patterns to simplify and return asarray
489+ * @param patterns the patterns to simplify and return as an array
477490 * @param excludes whether the patterns are exclude patterns
478491 * @return the set content as an array, after simplification
479492 */
@@ -497,7 +510,7 @@ private static String[] simplify(Set<String> patterns, boolean excludes) {
497510 *
498511 * @param patterns the normalized include or exclude patterns
499512 * @param excludes whether the patterns are exclude patterns
500- * @return pattens of directories to include or exclude
513+ * @return patterns of directories to include or exclude
501514 */
502515 private static String [] directoryPatterns (final String [] patterns , final boolean excludes ) {
503516 // TODO: use `LinkedHashSet.newLinkedHashSet(int)` instead with JDK19.
@@ -523,6 +536,21 @@ private static String[] directoryPatterns(final String[] patterns, final boolean
523536 return simplify (directories , excludes );
524537 }
525538
539+ /**
540+ * Returns {@code true} if at least one pattern requires path being relativized before to be matched.
541+ *
542+ * @param patterns include or exclude patterns
543+ * @return whether at least one pattern require relativization
544+ */
545+ private static boolean needRelativize (String [] patterns ) {
546+ for (String pattern : patterns ) {
547+ if (!pattern .startsWith (DEFAULT_SYNTAX + "**/" )) {
548+ return true ;
549+ }
550+ }
551+ return false ;
552+ }
553+
526554 /**
527555 * Creates the path matchers for the given patterns.
528556 * The syntax (usually {@value #DEFAULT_SYNTAX}) must be specified for each pattern.
@@ -535,12 +563,20 @@ private static PathMatcher[] matchers(final FileSystem fs, final String[] patter
535563 return matchers ;
536564 }
537565
566+ /**
567+ * {@return whether there are no include or exclude filters}.
568+ * In such case, this {@code PathSelector} instance should be ignored.
569+ */
570+ public boolean isEmpty () {
571+ return includes .length == 0 && excludes .length == 0 ;
572+ }
573+
538574 /**
539575 * {@return a potentially simpler matcher equivalent to this matcher}.
540576 */
541577 @ SuppressWarnings ("checkstyle:MissingSwitchDefault" )
542578 public PathMatcher simplify () {
543- if (excludes .length == 0 ) {
579+ if (! needRelativize && excludes .length == 0 ) {
544580 switch (includes .length ) {
545581 case 0 :
546582 return INCLUDES_ALL ;
@@ -560,7 +596,9 @@ public PathMatcher simplify() {
560596 */
561597 @ Override
562598 public boolean matches (Path path ) {
563- path = baseDirectory .relativize (path );
599+ if (needRelativize ) {
600+ path = baseDirectory .relativize (path );
601+ }
564602 return (includes .length == 0 || isMatched (path , includes ))
565603 && (excludes .length == 0 || !isMatched (path , excludes ));
566604 }
0 commit comments