Java PathMatcher: why ** doesn't work for zero folders?

Viewed 143

I'm trying to match relative paths using a PathMatcher. A very common case is to use a pattern like **/foo.php to match all files named foo.php whatever is the folder they are in. But I found a behavior that look wrong to me, when the file is actually in no folders:

import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.nio.file.Paths;

public class PathMatcherTest {

  public static void main(String[] args) {
    testMatch("foo.php", Paths.get("foo.php"));
    testMatch("foo.php", Paths.get("sub/foo.php"));
    testMatch("**/foo.php", Paths.get("sub/foo.php"));
    testMatch("**/foo.php", Paths.get("foo.php"));
  }

  private static void testMatch(String pattern, Path path) {
    PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher("glob:" + pattern);
    if (pathMatcher.matches(path)) {
      System.out.println(pattern + " matches " + path);
    } else {
      System.out.println(pattern + " doesn't matches " + path);
    }
  }

}

produces:

foo.php matches foo.php // OK
foo.php doesn't matches sub/foo.php // OK
**/foo.php matches sub/foo.php // OK
**/foo.php doesn't matches foo.php // KO, why ????

Why is the GLOB pattern **/foo.php not matching foo.php? Am I misreading the spec, or is it a bug?

1 Answers

From the documentation:

The ** characters matches zero or more characters crossing directory boundaries.

With your pattern **/foo.php it's easy to see why it's not working. Because ** can be empty, the matcher essentially checks if foo.php matches /foo.php (which it clearly should not, one is located in the current folder, the other in the root).

To fix this: You can use a subpattern to match the case where the file resides in no folder. You can achieve this by changing your pattern to {foo.php,**/foo.php}

The { } characters are a group of subpatterns, where the group matches if any subpattern in the group matches. The "," character is used to separate the subpatterns. Groups cannot be nested.

Related