langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java
changeset 27852 2e6ad0e4fe20
parent 27226 53535e4e1b08
child 27858 443efec4bf09
equal deleted inserted replaced
27851:5f28577d20f6 27852:2e6ad0e4fe20
    27 import java.io.File;
    27 import java.io.File;
    28 import java.io.FileNotFoundException;
    28 import java.io.FileNotFoundException;
    29 import java.io.IOException;
    29 import java.io.IOException;
    30 import java.net.MalformedURLException;
    30 import java.net.MalformedURLException;
    31 import java.net.URL;
    31 import java.net.URL;
       
    32 import java.nio.file.Files;
       
    33 import java.nio.file.Path;
       
    34 import java.nio.file.Paths;
       
    35 import java.util.ArrayList;
    32 import java.util.Arrays;
    36 import java.util.Arrays;
    33 import java.util.Collection;
    37 import java.util.Collection;
    34 import java.util.Collections;
    38 import java.util.Collections;
    35 import java.util.EnumMap;
    39 import java.util.EnumMap;
    36 import java.util.EnumSet;
    40 import java.util.EnumSet;
    38 import java.util.HashSet;
    42 import java.util.HashSet;
    39 import java.util.Iterator;
    43 import java.util.Iterator;
    40 import java.util.LinkedHashSet;
    44 import java.util.LinkedHashSet;
    41 import java.util.Map;
    45 import java.util.Map;
    42 import java.util.Set;
    46 import java.util.Set;
    43 import java.util.StringTokenizer;
    47 import java.util.regex.Pattern;
       
    48 import java.util.stream.Stream;
    44 import java.util.zip.ZipFile;
    49 import java.util.zip.ZipFile;
    45 
    50 
    46 import javax.tools.JavaFileManager;
    51 import javax.tools.JavaFileManager;
    47 import javax.tools.JavaFileManager.Location;
    52 import javax.tools.JavaFileManager.Location;
    48 import javax.tools.StandardJavaFileManager;
    53 import javax.tools.StandardJavaFileManager;
   103         this.log = log;
   108         this.log = log;
   104         warn = lint.isEnabled(Lint.LintCategory.PATH);
   109         warn = lint.isEnabled(Lint.LintCategory.PATH);
   105         this.fsInfo = fsInfo;
   110         this.fsInfo = fsInfo;
   106     }
   111     }
   107 
   112 
   108     public Collection<File> bootClassPath() {
   113     public Collection<Path> bootClassPath() {
   109         return getLocation(PLATFORM_CLASS_PATH);
   114         return getLocation(PLATFORM_CLASS_PATH);
   110     }
   115     }
   111 
   116 
   112     public boolean isDefaultBootClassPath() {
   117     public boolean isDefaultBootClassPath() {
   113         BootClassPathLocationHandler h
   118         BootClassPathLocationHandler h
   114                 = (BootClassPathLocationHandler) getHandler(PLATFORM_CLASS_PATH);
   119                 = (BootClassPathLocationHandler) getHandler(PLATFORM_CLASS_PATH);
   115         return h.isDefault();
   120         return h.isDefault();
   116     }
   121     }
   117 
   122 
   118     boolean isDefaultBootClassPathRtJar(File file) {
   123     boolean isDefaultBootClassPathRtJar(Path file) {
   119         BootClassPathLocationHandler h
   124         BootClassPathLocationHandler h
   120                 = (BootClassPathLocationHandler) getHandler(PLATFORM_CLASS_PATH);
   125                 = (BootClassPathLocationHandler) getHandler(PLATFORM_CLASS_PATH);
   121         return h.isDefaultRtJar(file);
   126         return h.isDefaultRtJar(file);
   122     }
   127     }
   123 
   128 
   124     public Collection<File> userClassPath() {
   129     public Collection<Path> userClassPath() {
   125         return getLocation(CLASS_PATH);
   130         return getLocation(CLASS_PATH);
   126     }
   131     }
   127 
   132 
   128     public Collection<File> sourcePath() {
   133     public Collection<Path> sourcePath() {
   129         Collection<File> p = getLocation(SOURCE_PATH);
   134         Collection<Path> p = getLocation(SOURCE_PATH);
   130         // TODO: this should be handled by the LocationHandler
   135         // TODO: this should be handled by the LocationHandler
   131         return p == null || p.isEmpty() ? null : p;
   136         return p == null || p.isEmpty() ? null : p;
   132     }
   137     }
   133 
   138 
   134     /**
   139     /**
   135      * Split a path into its elements. Empty path elements will be ignored.
   140      * Split a search path into its elements. Empty path elements will be ignored.
   136      *
   141      *
   137      * @param path The path to be split
   142      * @param searchPath The search path to be split
   138      * @return The elements of the path
   143      * @return The elements of the path
   139      */
   144      */
   140     private static Iterable<File> getPathEntries(String path) {
   145     private static Iterable<Path> getPathEntries(String searchPath) {
   141         return getPathEntries(path, null);
   146         return getPathEntries(searchPath, null);
   142     }
   147     }
   143 
   148 
   144     /**
   149     /**
   145      * Split a path into its elements. If emptyPathDefault is not null, all empty elements in the
   150      * Split a search path into its elements. If emptyPathDefault is not null, all empty elements in the
   146      * path, including empty elements at either end of the path, will be replaced with the value of
   151      * path, including empty elements at either end of the path, will be replaced with the value of
   147      * emptyPathDefault.
   152      * emptyPathDefault.
   148      *
   153      *
   149      * @param path The path to be split
   154      * @param searchPath The search path to be split
   150      * @param emptyPathDefault The value to substitute for empty path elements, or null, to ignore
   155      * @param emptyPathDefault The value to substitute for empty path elements, or null, to ignore
   151      * empty path elements
   156      * empty path elements
   152      * @return The elements of the path
   157      * @return The elements of the path
   153      */
   158      */
   154     private static Iterable<File> getPathEntries(String path, File emptyPathDefault) {
   159     private static Iterable<Path> getPathEntries(String searchPath, Path emptyPathDefault) {
   155         ListBuffer<File> entries = new ListBuffer<>();
   160         ListBuffer<Path> entries = new ListBuffer<>();
   156         int start = 0;
   161         for (String s: searchPath.split(Pattern.quote(File.pathSeparator), -1)) {
   157         while (start <= path.length()) {
   162             if (s.isEmpty()) {
   158             int sep = path.indexOf(File.pathSeparatorChar, start);
   163                 if (emptyPathDefault != null) {
   159             if (sep == -1) {
   164                     entries.add(emptyPathDefault);
   160                 sep = path.length();
   165                 }
   161             }
   166             } else {
   162             if (start < sep) {
   167                 entries.add(Paths.get(s));
   163                 entries.add(new File(path.substring(start, sep)));
   168             }
   164             } else if (emptyPathDefault != null) {
       
   165                 entries.add(emptyPathDefault);
       
   166             }
       
   167             start = sep + 1;
       
   168         }
   169         }
   169         return entries;
   170         return entries;
   170     }
   171     }
   171 
   172 
   172     /**
   173     /**
   173      * Utility class to help evaluate a path option. Duplicate entries are ignored, jar class paths
   174      * Utility class to help evaluate a path option. Duplicate entries are ignored, jar class paths
   174      * can be expanded.
   175      * can be expanded.
   175      */
   176      */
   176     private class SearchPath extends LinkedHashSet<File> {
   177     private class SearchPath extends LinkedHashSet<Path> {
   177 
   178 
   178         private static final long serialVersionUID = 0;
   179         private static final long serialVersionUID = 0;
   179 
   180 
   180         private boolean expandJarClassPaths = false;
   181         private boolean expandJarClassPaths = false;
   181         private final Set<File> canonicalValues = new HashSet<>();
   182         private final Set<Path> canonicalValues = new HashSet<>();
   182 
   183 
   183         public SearchPath expandJarClassPaths(boolean x) {
   184         public SearchPath expandJarClassPaths(boolean x) {
   184             expandJarClassPaths = x;
   185             expandJarClassPaths = x;
   185             return this;
   186             return this;
   186         }
   187         }
   187 
   188 
   188         /**
   189         /**
   189          * What to use when path element is the empty string
   190          * What to use when path element is the empty string
   190          */
   191          */
   191         private File emptyPathDefault = null;
   192         private Path emptyPathDefault = null;
   192 
   193 
   193         public SearchPath emptyPathDefault(File x) {
   194         public SearchPath emptyPathDefault(Path x) {
   194             emptyPathDefault = x;
   195             emptyPathDefault = x;
   195             return this;
   196             return this;
   196         }
   197         }
   197 
   198 
   198         public SearchPath addDirectories(String dirs, boolean warn) {
   199         public SearchPath addDirectories(String dirs, boolean warn) {
   199             boolean prev = expandJarClassPaths;
   200             boolean prev = expandJarClassPaths;
   200             expandJarClassPaths = true;
   201             expandJarClassPaths = true;
   201             try {
   202             try {
   202                 if (dirs != null) {
   203                 if (dirs != null) {
   203                     for (File dir : getPathEntries(dirs)) {
   204                     for (Path dir : getPathEntries(dirs)) {
   204                         addDirectory(dir, warn);
   205                         addDirectory(dir, warn);
   205                     }
   206                     }
   206                 }
   207                 }
   207                 return this;
   208                 return this;
   208             } finally {
   209             } finally {
   212 
   213 
   213         public SearchPath addDirectories(String dirs) {
   214         public SearchPath addDirectories(String dirs) {
   214             return addDirectories(dirs, warn);
   215             return addDirectories(dirs, warn);
   215         }
   216         }
   216 
   217 
   217         private void addDirectory(File dir, boolean warn) {
   218         private void addDirectory(Path dir, boolean warn) {
   218             if (!dir.isDirectory()) {
   219             if (!Files.isDirectory(dir)) {
   219                 if (warn) {
   220                 if (warn) {
   220                     log.warning(Lint.LintCategory.PATH,
   221                     log.warning(Lint.LintCategory.PATH,
   221                             "dir.path.element.not.found", dir);
   222                             "dir.path.element.not.found", dir);
   222                 }
   223                 }
   223                 return;
   224                 return;
   224             }
   225             }
   225 
   226 
   226             File[] files = dir.listFiles();
   227             try (Stream<Path> s = Files.list(dir)) {
   227             if (files == null) {
   228                 s.filter(dirEntry -> isArchive(dirEntry))
   228                 return;
   229                         .forEach(dirEntry -> addFile(dirEntry, warn));
   229             }
   230             } catch (IOException ignore) {
   230 
       
   231             for (File direntry : files) {
       
   232                 if (isArchive(direntry)) {
       
   233                     addFile(direntry, warn);
       
   234                 }
       
   235             }
   231             }
   236         }
   232         }
   237 
   233 
   238         public SearchPath addFiles(String files, boolean warn) {
   234         public SearchPath addFiles(String files, boolean warn) {
   239             if (files != null) {
   235             if (files != null) {
   244 
   240 
   245         public SearchPath addFiles(String files) {
   241         public SearchPath addFiles(String files) {
   246             return addFiles(files, warn);
   242             return addFiles(files, warn);
   247         }
   243         }
   248 
   244 
   249         public SearchPath addFiles(Iterable<? extends File> files, boolean warn) {
   245         public SearchPath addFiles(Iterable<? extends Path> files, boolean warn) {
   250             if (files != null) {
   246             if (files != null) {
   251                 for (File file : files) {
   247                 for (Path file : files) {
   252                     addFile(file, warn);
   248                     addFile(file, warn);
   253                 }
   249                 }
   254             }
   250             }
   255             return this;
   251             return this;
   256         }
   252         }
   257 
   253 
   258         public SearchPath addFiles(Iterable<? extends File> files) {
   254         public SearchPath addFiles(Iterable<? extends Path> files) {
   259             return addFiles(files, warn);
   255             return addFiles(files, warn);
   260         }
   256         }
   261 
   257 
   262         public void addFile(File file, boolean warn) {
   258         public void addFile(Path file, boolean warn) {
   263             if (contains(file)) {
   259             if (contains(file)) {
   264                 // discard duplicates
   260                 // discard duplicates
   265                 return;
   261                 return;
   266             }
   262             }
   267 
   263 
   273                 }
   269                 }
   274                 super.add(file);
   270                 super.add(file);
   275                 return;
   271                 return;
   276             }
   272             }
   277 
   273 
   278             File canonFile = fsInfo.getCanonicalFile(file);
   274             Path canonFile = fsInfo.getCanonicalFile(file);
   279             if (canonicalValues.contains(canonFile)) {
   275             if (canonicalValues.contains(canonFile)) {
   280                 /* Discard duplicates and avoid infinite recursion */
   276                 /* Discard duplicates and avoid infinite recursion */
   281                 return;
   277                 return;
   282             }
   278             }
   283 
   279 
   285                 /* File is an ordinary file. */
   281                 /* File is an ordinary file. */
   286                 if (!isArchive(file)) {
   282                 if (!isArchive(file)) {
   287                     /* Not a recognized extension; open it to see if
   283                     /* Not a recognized extension; open it to see if
   288                      it looks like a valid zip file. */
   284                      it looks like a valid zip file. */
   289                     try {
   285                     try {
   290                         ZipFile z = new ZipFile(file);
   286                         ZipFile z = new ZipFile(file.toFile());
   291                         z.close();
   287                         z.close();
   292                         if (warn) {
   288                         if (warn) {
   293                             log.warning(Lint.LintCategory.PATH,
   289                             log.warning(Lint.LintCategory.PATH,
   294                                     "unexpected.archive.file", file);
   290                                     "unexpected.archive.file", file);
   295                         }
   291                         }
   316 
   312 
   317         // Adds referenced classpath elements from a jar's Class-Path
   313         // Adds referenced classpath elements from a jar's Class-Path
   318         // Manifest entry.  In some future release, we may want to
   314         // Manifest entry.  In some future release, we may want to
   319         // update this code to recognize URLs rather than simple
   315         // update this code to recognize URLs rather than simple
   320         // filenames, but if we do, we should redo all path-related code.
   316         // filenames, but if we do, we should redo all path-related code.
   321         private void addJarClassPath(File jarFile, boolean warn) {
   317         private void addJarClassPath(Path jarFile, boolean warn) {
   322             try {
   318             try {
   323                 for (File f : fsInfo.getJarClassPath(jarFile)) {
   319                 for (Path f : fsInfo.getJarClassPath(jarFile)) {
   324                     addFile(f, warn);
   320                     addFile(f, warn);
   325                 }
   321                 }
   326             } catch (IOException e) {
   322             } catch (IOException e) {
   327                 log.error("error.reading.file", jarFile, JavacFileManager.getMessage(e));
   323                 log.error("error.reading.file", jarFile, JavacFileManager.getMessage(e));
   328             }
   324             }
   363         abstract boolean handleOption(Option option, String value);
   359         abstract boolean handleOption(Option option, String value);
   364 
   360 
   365         /**
   361         /**
   366          * @see StandardJavaFileManager#getLocation
   362          * @see StandardJavaFileManager#getLocation
   367          */
   363          */
   368         abstract Collection<File> getLocation();
   364         abstract Collection<Path> getLocation();
   369 
   365 
   370         /**
   366         /**
   371          * @see StandardJavaFileManager#setLocation
   367          * @see StandardJavaFileManager#setLocation
   372          */
   368          */
   373         abstract void setLocation(Iterable<? extends File> files) throws IOException;
   369         abstract void setLocation(Iterable<? extends Path> files) throws IOException;
   374     }
   370     }
   375 
   371 
   376     /**
   372     /**
   377      * General purpose implementation for output locations, such as -d/CLASS_OUTPUT and
   373      * General purpose implementation for output locations, such as -d/CLASS_OUTPUT and
   378      * -s/SOURCE_OUTPUT. All options are treated as equivalent (i.e. aliases.) The value is a single
   374      * -s/SOURCE_OUTPUT. All options are treated as equivalent (i.e. aliases.) The value is a single
   379      * file, possibly null.
   375      * file, possibly null.
   380      */
   376      */
   381     private class OutputLocationHandler extends LocationHandler {
   377     private class OutputLocationHandler extends LocationHandler {
   382 
   378 
   383         private File outputDir;
   379         private Path outputDir;
   384 
   380 
   385         OutputLocationHandler(Location location, Option... options) {
   381         OutputLocationHandler(Location location, Option... options) {
   386             super(location, options);
   382             super(location, options);
   387         }
   383         }
   388 
   384 
   394 
   390 
   395             // TODO: could/should validate outputDir exists and is a directory
   391             // TODO: could/should validate outputDir exists and is a directory
   396             // need to decide how best to report issue for benefit of
   392             // need to decide how best to report issue for benefit of
   397             // direct API call on JavaFileManager.handleOption(specifies IAE)
   393             // direct API call on JavaFileManager.handleOption(specifies IAE)
   398             // vs. command line decoding.
   394             // vs. command line decoding.
   399             outputDir = (value == null) ? null : new File(value);
   395             outputDir = (value == null) ? null : Paths.get(value);
   400             return true;
   396             return true;
   401         }
   397         }
   402 
   398 
   403         @Override
   399         @Override
   404         Collection<File> getLocation() {
   400         Collection<Path> getLocation() {
   405             return (outputDir == null) ? null : Collections.singleton(outputDir);
   401             return (outputDir == null) ? null : Collections.singleton(outputDir);
   406         }
   402         }
   407 
   403 
   408         @Override
   404         @Override
   409         void setLocation(Iterable<? extends File> files) throws IOException {
   405         void setLocation(Iterable<? extends Path> files) throws IOException {
   410             if (files == null) {
   406             if (files == null) {
   411                 outputDir = null;
   407                 outputDir = null;
   412             } else {
   408             } else {
   413                 Iterator<? extends File> pathIter = files.iterator();
   409                 Iterator<? extends Path> pathIter = files.iterator();
   414                 if (!pathIter.hasNext()) {
   410                 if (!pathIter.hasNext()) {
   415                     throw new IllegalArgumentException("empty path for directory");
   411                     throw new IllegalArgumentException("empty path for directory");
   416                 }
   412                 }
   417                 File dir = pathIter.next();
   413                 Path dir = pathIter.next();
   418                 if (pathIter.hasNext()) {
   414                 if (pathIter.hasNext()) {
   419                     throw new IllegalArgumentException("path too long for directory");
   415                     throw new IllegalArgumentException("path too long for directory");
   420                 }
   416                 }
   421                 if (!dir.exists()) {
   417                 if (!Files.exists(dir)) {
   422                     throw new FileNotFoundException(dir + ": does not exist");
   418                     throw new FileNotFoundException(dir + ": does not exist");
   423                 } else if (!dir.isDirectory()) {
   419                 } else if (!Files.isDirectory(dir)) {
   424                     throw new IOException(dir + ": not a directory");
   420                     throw new IOException(dir + ": not a directory");
   425                 }
   421                 }
   426                 outputDir = dir;
   422                 outputDir = dir;
   427             }
   423             }
   428         }
   424         }
   433      * -processorPath/ANNOTATION_PROCESS_PATH. All options are treated as equivalent (i.e. aliases.)
   429      * -processorPath/ANNOTATION_PROCESS_PATH. All options are treated as equivalent (i.e. aliases.)
   434      * The value is an ordered set of files and/or directories.
   430      * The value is an ordered set of files and/or directories.
   435      */
   431      */
   436     private class SimpleLocationHandler extends LocationHandler {
   432     private class SimpleLocationHandler extends LocationHandler {
   437 
   433 
   438         protected Collection<File> searchPath;
   434         protected Collection<Path> searchPath;
   439 
   435 
   440         SimpleLocationHandler(Location location, Option... options) {
   436         SimpleLocationHandler(Location location, Option... options) {
   441             super(location, options);
   437             super(location, options);
   442         }
   438         }
   443 
   439 
   450                     : Collections.unmodifiableCollection(createPath().addFiles(value));
   446                     : Collections.unmodifiableCollection(createPath().addFiles(value));
   451             return true;
   447             return true;
   452         }
   448         }
   453 
   449 
   454         @Override
   450         @Override
   455         Collection<File> getLocation() {
   451         Collection<Path> getLocation() {
   456             return searchPath;
   452             return searchPath;
   457         }
   453         }
   458 
   454 
   459         @Override
   455         @Override
   460         void setLocation(Iterable<? extends File> files) {
   456         void setLocation(Iterable<? extends Path> files) {
   461             SearchPath p;
   457             SearchPath p;
   462             if (files == null) {
   458             if (files == null) {
   463                 p = computePath(null);
   459                 p = computePath(null);
   464             } else {
   460             } else {
   465                 p = createPath().addFiles(files);
   461                 p = createPath().addFiles(files);
   486             super(StandardLocation.CLASS_PATH,
   482             super(StandardLocation.CLASS_PATH,
   487                     Option.CLASSPATH, Option.CP);
   483                     Option.CLASSPATH, Option.CP);
   488         }
   484         }
   489 
   485 
   490         @Override
   486         @Override
   491         Collection<File> getLocation() {
   487         Collection<Path> getLocation() {
   492             lazy();
   488             lazy();
   493             return searchPath;
   489             return searchPath;
   494         }
   490         }
   495 
   491 
   496         @Override
   492         @Override
   518 
   514 
   519         @Override
   515         @Override
   520         protected SearchPath createPath() {
   516         protected SearchPath createPath() {
   521             return new SearchPath()
   517             return new SearchPath()
   522                     .expandJarClassPaths(true) // Only search user jars for Class-Paths
   518                     .expandJarClassPaths(true) // Only search user jars for Class-Paths
   523                     .emptyPathDefault(new File("."));  // Empty path elt ==> current directory
   519                     .emptyPathDefault(Paths.get("."));  // Empty path elt ==> current directory
   524         }
   520         }
   525 
   521 
   526         private void lazy() {
   522         private void lazy() {
   527             if (searchPath == null) {
   523             if (searchPath == null) {
   528                 setLocation(null);
   524                 setLocation(null);
   537      * reverts to using default values for options that have not been set. Setting -bootclasspath or
   533      * reverts to using default values for options that have not been set. Setting -bootclasspath or
   538      * -Xbootclasspath overrides any existing value for -Xbootclasspath/p: and -Xbootclasspath/a:.
   534      * -Xbootclasspath overrides any existing value for -Xbootclasspath/p: and -Xbootclasspath/a:.
   539      */
   535      */
   540     private class BootClassPathLocationHandler extends LocationHandler {
   536     private class BootClassPathLocationHandler extends LocationHandler {
   541 
   537 
   542         private Collection<File> searchPath;
   538         private Collection<Path> searchPath;
   543         final Map<Option, String> optionValues = new EnumMap<>(Option.class);
   539         final Map<Option, String> optionValues = new EnumMap<>(Option.class);
   544 
   540 
   545         /**
   541         /**
   546          * rt.jar as found on the default bootclasspath. If the user specified a bootclasspath, null
   542          * rt.jar as found on the default bootclasspath. If the user specified a bootclasspath, null
   547          * is used.
   543          * is used.
   548          */
   544          */
   549         private File defaultBootClassPathRtJar = null;
   545         private Path defaultBootClassPathRtJar = null;
   550 
   546 
   551         /**
   547         /**
   552          * Is bootclasspath the default?
   548          * Is bootclasspath the default?
   553          */
   549          */
   554         private boolean isDefaultBootClassPath;
   550         private boolean isDefaultBootClassPath;
   565         boolean isDefault() {
   561         boolean isDefault() {
   566             lazy();
   562             lazy();
   567             return isDefaultBootClassPath;
   563             return isDefaultBootClassPath;
   568         }
   564         }
   569 
   565 
   570         boolean isDefaultRtJar(File file) {
   566         boolean isDefaultRtJar(Path file) {
   571             lazy();
   567             lazy();
   572             return file.equals(defaultBootClassPathRtJar);
   568             return file.equals(defaultBootClassPathRtJar);
   573         }
   569         }
   574 
   570 
   575         @Override
   571         @Override
   602                     return option;
   598                     return option;
   603             }
   599             }
   604         }
   600         }
   605 
   601 
   606         @Override
   602         @Override
   607         Collection<File> getLocation() {
   603         Collection<Path> getLocation() {
   608             lazy();
   604             lazy();
   609             return searchPath;
   605             return searchPath;
   610         }
   606         }
   611 
   607 
   612         @Override
   608         @Override
   613         void setLocation(Iterable<? extends File> files) {
   609         void setLocation(Iterable<? extends Path> files) {
   614             if (files == null) {
   610             if (files == null) {
   615                 searchPath = null;  // reset to "uninitialized"
   611                 searchPath = null;  // reset to "uninitialized"
   616             } else {
   612             } else {
   617                 defaultBootClassPathRtJar = null;
   613                 defaultBootClassPathRtJar = null;
   618                 isDefaultBootClassPath = false;
   614                 isDefaultBootClassPath = false;
   643                 path.addFiles(bootclasspathOpt);
   639                 path.addFiles(bootclasspathOpt);
   644             } else {
   640             } else {
   645                 // Standard system classes for this compiler's release.
   641                 // Standard system classes for this compiler's release.
   646                 String files = System.getProperty("sun.boot.class.path");
   642                 String files = System.getProperty("sun.boot.class.path");
   647                 path.addFiles(files, false);
   643                 path.addFiles(files, false);
   648                 File rt_jar = new File("rt.jar");
   644                 Path rt_jar = Paths.get("rt.jar");
   649                 for (File file : getPathEntries(files)) {
   645                 for (Path file : getPathEntries(files)) {
   650                     if (new File(file.getName()).equals(rt_jar)) {
   646                     if (file.getFileName().equals(rt_jar)) {
   651                         defaultBootClassPathRtJar = file;
   647                         defaultBootClassPathRtJar = file;
   652                     }
   648                     }
   653                 }
   649                 }
   654             }
   650             }
   655 
   651 
   707     public boolean handleOption(Option option, String value) {
   703     public boolean handleOption(Option option, String value) {
   708         LocationHandler h = handlersForOption.get(option);
   704         LocationHandler h = handlersForOption.get(option);
   709         return (h == null ? false : h.handleOption(option, value));
   705         return (h == null ? false : h.handleOption(option, value));
   710     }
   706     }
   711 
   707 
   712     Collection<File> getLocation(Location location) {
   708     Collection<Path> getLocation(Location location) {
   713         LocationHandler h = getHandler(location);
   709         LocationHandler h = getHandler(location);
   714         return (h == null ? null : h.getLocation());
   710         return (h == null ? null : h.getLocation());
   715     }
   711     }
   716 
   712 
   717     File getOutputLocation(Location location) {
   713     Path getOutputLocation(Location location) {
   718         if (!location.isOutputLocation()) {
   714         if (!location.isOutputLocation()) {
   719             throw new IllegalArgumentException();
   715             throw new IllegalArgumentException();
   720         }
   716         }
   721         LocationHandler h = getHandler(location);
   717         LocationHandler h = getHandler(location);
   722         return ((OutputLocationHandler) h).outputDir;
   718         return ((OutputLocationHandler) h).outputDir;
   723     }
   719     }
   724 
   720 
   725     void setLocation(Location location, Iterable<? extends File> files) throws IOException {
   721     void setLocation(Location location, Iterable<? extends Path> files) throws IOException {
   726         LocationHandler h = getHandler(location);
   722         LocationHandler h = getHandler(location);
   727         if (h == null) {
   723         if (h == null) {
   728             if (location.isOutputLocation()) {
   724             if (location.isOutputLocation()) {
   729                 h = new OutputLocationHandler(location);
   725                 h = new OutputLocationHandler(location);
   730             } else {
   726             } else {
   741     }
   737     }
   742 
   738 
   743     /**
   739     /**
   744      * Is this the name of an archive file?
   740      * Is this the name of an archive file?
   745      */
   741      */
   746     private boolean isArchive(File file) {
   742     private boolean isArchive(Path file) {
   747         String n = StringUtils.toLowerCase(file.getName());
   743         String n = StringUtils.toLowerCase(file.getFileName().toString());
   748         return fsInfo.isFile(file)
   744         return fsInfo.isFile(file)
   749                 && (n.endsWith(".jar") || n.endsWith(".zip"));
   745                 && (n.endsWith(".jar") || n.endsWith(".zip"));
   750     }
   746     }
   751 
   747 
   752     /**
   748     /**
   753      * Utility method for converting a search path string to an array of directory and JAR file
   749      * Utility method for converting a search path string to an array of directory and JAR file
   754      * URLs.
   750      * URLs.
   755      *
   751      *
   756      * Note that this method is called by apt and the DocletInvoker.
   752      * Note that this method is called by the DocletInvoker.
   757      *
   753      *
   758      * @param path the search path string
   754      * @param path the search path string
   759      * @return the resulting array of directory and JAR file URLs
   755      * @return the resulting array of directory and JAR file URLs
   760      */
   756      */
   761     public static URL[] pathToURLs(String path) {
   757     public static URL[] pathToURLs(String path) {
   762         StringTokenizer st = new StringTokenizer(path, File.pathSeparator);
   758         java.util.List<URL> urls = new ArrayList<>();
   763         URL[] urls = new URL[st.countTokens()];
   759         for (String s: path.split(Pattern.quote(File.pathSeparator))) {
   764         int count = 0;
   760             if (!s.isEmpty()) {
   765         while (st.hasMoreTokens()) {
   761                 URL url = fileToURL(Paths.get(s));
   766             URL url = fileToURL(new File(st.nextToken()));
   762                 if (url != null) {
   767             if (url != null) {
   763                     urls.add(url);
   768                 urls[count++] = url;
   764                 }
   769             }
   765             }
   770         }
   766         }
   771         urls = Arrays.copyOf(urls, count);
   767         return urls.toArray(new URL[urls.size()]);
   772         return urls;
       
   773     }
   768     }
   774 
   769 
   775     /**
   770     /**
   776      * Returns the directory or JAR file URL corresponding to the specified local file name.
   771      * Returns the directory or JAR file URL corresponding to the specified local file name.
   777      *
   772      *
   778      * @param file the File object
   773      * @param file the Path object
   779      * @return the resulting directory or JAR file URL, or null if unknown
   774      * @return the resulting directory or JAR file URL, or null if unknown
   780      */
   775      */
   781     private static URL fileToURL(File file) {
   776     private static URL fileToURL(Path file) {
   782         String name;
   777         Path p;
   783         try {
   778         try {
   784             name = file.getCanonicalPath();
   779             p = file.toRealPath();
   785         } catch (IOException e) {
   780         } catch (IOException e) {
   786             name = file.getAbsolutePath();
   781             p = file.toAbsolutePath();
   787         }
       
   788         name = name.replace(File.separatorChar, '/');
       
   789         if (!name.startsWith("/")) {
       
   790             name = "/" + name;
       
   791         }
       
   792         // If the file does not exist, then assume that it's a directory
       
   793         if (!file.isFile()) {
       
   794             name = name + "/";
       
   795         }
   782         }
   796         try {
   783         try {
   797             return new URL("file", "", name);
   784             return p.normalize().toUri().toURL();
   798         } catch (MalformedURLException e) {
   785         } catch (MalformedURLException e) {
   799             throw new IllegalArgumentException(file.toString());
   786             return null;
   800         }
   787         }
   801     }
   788     }
   802 }
   789 }