8149843: StandardJavaFileManager should provide a way to get paths from strings

8150111: Need to change signature of StandardJavaFileManager.setLocationFromPaths

Reviewed-by: vromero, jlahoda
This commit is contained in:
Jonathan Gibbons 2016-05-12 11:36:08 -07:00
parent 139c282119
commit b733375f7d
8 changed files with 134 additions and 56 deletions
langtools/src
java.compiler/share/classes/javax/tools
jdk.compiler/share/classes/com/sun/tools/javac
jdk.jshell/share/classes/jdk/jshell

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -29,6 +29,7 @@ import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collection;
import static javax.tools.FileManagerUtils.*;
@ -176,7 +177,8 @@ public interface StandardJavaFileManager extends JavaFileManager {
/**
* Returns file objects representing the given paths.
*
* <p>The default implementation converts each path to a file and calls
* @implSpec
* The default implementation converts each path to a file and calls
* {@link #getJavaFileObjectsFromFiles getJavaObjectsFromFiles}.
* IllegalArgumentException will be thrown if any of the paths
* cannot be converted to a file.
@ -280,10 +282,21 @@ public interface StandardJavaFileManager extends JavaFileManager {
* Associates the given search path with the given location. Any
* previous value will be discarded.
*
* <p>The default implementation converts each path to a file and calls
* @apiNote
* The type of the {@code paths} parameter is a {@code Collection}
* and not {@code Iterable}. This is to prevent the possibility of
* accidentally calling the method with a single {@code Path} as
* the second argument, because although {@code Path} implements
* {@code Iterable<Path>}, it would almost never be correct to call
* this method with a single {@code Path} and have it be treated as
* an {@code Iterable} of its components.
*
*
* @implSpec
* The default implementation converts each path to a file and calls
* {@link #getJavaFileObjectsFromFiles getJavaObjectsFromFiles}.
* IllegalArgumentException will be thrown if any of the paths
* cannot be converted to a file.</p>
* cannot be converted to a file.
*
* @param location a location
* @param paths a list of paths, if {@code null} use the default
@ -297,8 +310,8 @@ public interface StandardJavaFileManager extends JavaFileManager {
*
* @since 9
*/
default void setLocationFromPaths(Location location, Iterable<? extends Path> paths)
throws IOException {
default void setLocationFromPaths(Location location, Collection<? extends Path> paths)
throws IOException {
setLocation(location, asFiles(paths));
}
@ -319,6 +332,11 @@ public interface StandardJavaFileManager extends JavaFileManager {
/**
* Returns the search path associated with the given location.
*
* @implSpec
* The default implementation calls {@link #getLocation getLocation}
* and then returns an {@code Iterable} formed by calling {@code toPath()}
* on each {@code File} returned from {@code getLocation}.
*
* @param location a location
* @return a list of paths or {@code null} if this location has no
* associated search path
@ -337,8 +355,9 @@ public interface StandardJavaFileManager extends JavaFileManager {
* {@link java.nio.file.Path Path} object. In such cases, this method may be
* used to access that object.
*
* <p>The default implementation throws {@link UnsupportedOperationException}
* for all files.</p>
* @implSpec
* The default implementation throws {@link UnsupportedOperationException}
* for all files.
*
* @param file a file object
* @return a path representing the same underlying file system artifact
@ -351,4 +370,36 @@ public interface StandardJavaFileManager extends JavaFileManager {
throw new UnsupportedOperationException();
}
/**
* Factory to create {@code Path} objects from strings.
*
* @since 9
*/
interface PathFactory {
/**
* Converts a path string, or a sequence of strings that when joined form a path string, to a Path.
*
* @param first the path string or initial part of the path string
* @param more additional strings to be joined to form the path string
* @return the resulting {@code Path}
*/
Path getPath(String first, String... more);
}
/**
* Specify a factory that can be used to generate a path from a string, or series of strings.
*
* If this method is not called, a factory whose {@code getPath} method is
* equivalent to calling
* {@link java.nio.file.Paths#get(String, String...) java.nio.file.Paths.get(first, more)}
* will be used.
*
* @implSpec
* The default implementation of this method ignores the factory that is provided.
*
* @param f the factory
*
* @since 9
*/
default void setPathFactory(PathFactory f) { }
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -492,7 +492,7 @@ public class ClientCodeWrapper {
}
@Override @DefinedBy(Api.COMPILER)
public void setLocationFromPaths(Location location, Iterable<? extends Path> paths) throws IOException {
public void setLocationFromPaths(Location location, Collection<? extends Path> paths) throws IOException {
try {
((StandardJavaFileManager)clientJavaFileManager).setLocationFromPaths(location, paths);
} catch (ClientCodeException e) {
@ -534,6 +534,17 @@ public class ClientCodeWrapper {
throw new ClientCodeException(e);
}
}
@Override @DefinedBy(Api.COMPILER)
public void setPathFactory(PathFactory f) {
try {
((StandardJavaFileManager)clientJavaFileManager).setPathFactory(f);
} catch (ClientCodeException e) {
throw e;
} catch (RuntimeException | Error e) {
throw new ClientCodeException(e);
}
}
}
protected class WrappedFileObject implements FileObject {

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -26,6 +26,7 @@
package com.sun.tools.javac.file;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
@ -108,7 +109,7 @@ public class FSInfo {
for (StringTokenizer st = new StringTokenizer(path);
st.hasMoreTokens(); ) {
String elt = st.nextToken();
Path f = Paths.get(elt);
Path f = FileSystems.getDefault().getPath(elt);
if (!f.isAbsolute() && parent != null)
f = parent.resolve(f).toAbsolutePath();
list.add(f);

@ -109,6 +109,8 @@ public class JavacFileManager extends BaseFileManager implements StandardJavaFil
protected boolean symbolFileEnabled;
private PathFactory pathFactory = Paths::get;
protected enum SortFiles implements Comparator<Path> {
FORWARD {
@Override
@ -166,6 +168,16 @@ public class JavacFileManager extends BaseFileManager implements StandardJavaFil
}
}
@Override @DefinedBy(DefinedBy.Api.COMPILER)
public void setPathFactory(PathFactory f) {
pathFactory = Objects.requireNonNull(f);
locations.setPathFactory(f);
}
private Path getPath(String first, String... more) {
return pathFactory.getPath(first, more);
}
/**
* Set whether or not to use ct.sym as an alternate to rt.jar.
*/
@ -199,7 +211,7 @@ public class JavacFileManager extends BaseFileManager implements StandardJavaFil
public Iterable<? extends JavaFileObject> getJavaFileObjectsFromStrings(Iterable<String> names) {
ListBuffer<Path> paths = new ListBuffer<>();
for (String name : names)
paths.append(Paths.get(nullCheck(name)));
paths.append(getPath(nullCheck(name)));
return getJavaFileObjectsFromPaths(paths.toList());
}
@ -837,7 +849,7 @@ public class JavacFileManager extends BaseFileManager implements StandardJavaFil
if (sibling != null && sibling instanceof PathFileObject) {
return ((PathFileObject) sibling).getSibling(baseName);
} else {
Path p = Paths.get(baseName);
Path p = getPath(baseName);
Path real = fsInfo.getCanonicalFile(p);
return PathFileObject.forSimplePath(this, real, p);
}
@ -855,7 +867,7 @@ public class JavacFileManager extends BaseFileManager implements StandardJavaFil
try {
if (dir == null) {
dir = Paths.get(System.getProperty("user.dir"));
dir = getPath(System.getProperty("user.dir"));
}
Path path = fileName.resolveAgainst(fsInfo.getCanonicalFile(dir));
return PathFileObject.forDirectoryPath(this, path, dir, fileName);
@ -918,7 +930,7 @@ public class JavacFileManager extends BaseFileManager implements StandardJavaFil
@Override @DefinedBy(Api.COMPILER)
public void setLocationFromPaths(Location location,
Iterable<? extends Path> searchpath)
Collection<? extends Path> searchpath)
throws IOException
{
nullCheck(location);

@ -68,6 +68,7 @@ import javax.lang.model.SourceVersion;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileManager.Location;
import javax.tools.StandardJavaFileManager;
import javax.tools.StandardJavaFileManager.PathFactory;
import javax.tools.StandardLocation;
import com.sun.tools.javac.code.Lint;
@ -121,7 +122,9 @@ public class Locations {
private ModuleNameReader moduleNameReader;
static final Path javaHome = Paths.get(System.getProperty("java.home"));
private PathFactory pathFactory = Paths::get;
static final Path javaHome = FileSystems.getDefault().getPath(System.getProperty("java.home"));
static final Path thisSystemModules = javaHome.resolve("lib").resolve("modules");
Map<Path, FileSystem> fileSystems = new LinkedHashMap<>();
@ -131,6 +134,10 @@ public class Locations {
initHandlers();
}
Path getPath(String first, String... more) {
return pathFactory.getPath(first, more);
}
public void close() throws IOException {
ListBuffer<IOException> list = new ListBuffer<>();
closeables.forEach(closeable -> {
@ -155,6 +162,10 @@ public class Locations {
this.fsInfo = fsInfo;
}
void setPathFactory(PathFactory f) {
pathFactory = f;
}
boolean isDefaultBootClassPath() {
BootClassPathLocationHandler h
= (BootClassPathLocationHandler) getHandler(PLATFORM_CLASS_PATH);
@ -167,7 +178,7 @@ public class Locations {
* @param searchPath The search path to be split
* @return The elements of the path
*/
private static Iterable<Path> getPathEntries(String searchPath) {
private Iterable<Path> getPathEntries(String searchPath) {
return getPathEntries(searchPath, null);
}
@ -181,7 +192,7 @@ public class Locations {
* empty path elements
* @return The elements of the path
*/
private static Iterable<Path> getPathEntries(String searchPath, Path emptyPathDefault) {
private Iterable<Path> getPathEntries(String searchPath, Path emptyPathDefault) {
ListBuffer<Path> entries = new ListBuffer<>();
for (String s: searchPath.split(Pattern.quote(File.pathSeparator), -1)) {
if (s.isEmpty()) {
@ -189,7 +200,7 @@ public class Locations {
entries.add(emptyPathDefault);
}
} else {
entries.add(Paths.get(s));
entries.add(getPath(s));
}
}
return entries;
@ -465,7 +476,7 @@ public class Locations {
// need to decide how best to report issue for benefit of
// direct API call on JavaFileManager.handleOption(specifies IAE)
// vs. command line decoding.
outputDir = (value == null) ? null : Paths.get(value);
outputDir = (value == null) ? null : getPath(value);
return true;
}
@ -606,7 +617,7 @@ public class Locations {
protected SearchPath createPath() {
return new SearchPath()
.expandJarClassPaths(true) // Only search user jars for Class-Paths
.emptyPathDefault(Paths.get(".")); // Empty path elt ==> current directory
.emptyPathDefault(getPath(".")); // Empty path elt ==> current directory
}
private void lazy() {
@ -791,7 +802,7 @@ public class Locations {
paths.addAll(modules);
for (String s : files.split(Pattern.quote(File.pathSeparator))) {
paths.add(Paths.get(s));
paths.add(getPath(s));
}
return paths;
@ -1170,12 +1181,12 @@ public class Locations {
for (String seg: segments) {
int markStart = seg.indexOf(MARKER);
if (markStart == -1) {
add(map, Paths.get(seg), null);
add(map, getPath(seg), null);
} else {
if (markStart == 0 || !isSeparator(seg.charAt(markStart - 1))) {
throw new IllegalArgumentException("illegal use of " + MARKER + " in " + seg);
}
Path prefix = Paths.get(seg.substring(0, markStart - 1));
Path prefix = getPath(seg.substring(0, markStart - 1));
Path suffix;
int markEnd = markStart + MARKER.length();
if (markEnd == seg.length()) {
@ -1184,7 +1195,7 @@ public class Locations {
|| seg.indexOf(MARKER, markEnd) != -1) {
throw new IllegalArgumentException("illegal use of " + MARKER + " in " + seg);
} else {
suffix = Paths.get(seg.substring(markEnd + 1));
suffix = getPath(seg.substring(markEnd + 1));
}
add(map, prefix, suffix);
}
@ -1331,13 +1342,13 @@ public class Locations {
}
private class SystemModulesLocationHandler extends BasicLocationHandler {
private Path javaHome;
private Path systemJavaHome;
private Path modules;
private Map<String, ModuleLocationHandler> systemModules;
SystemModulesLocationHandler() {
super(StandardLocation.SYSTEM_MODULES, Option.SYSTEM);
javaHome = Paths.get(System.getProperty("java.home"));
systemJavaHome = Locations.javaHome;
}
@Override
@ -1347,11 +1358,11 @@ public class Locations {
}
if (value == null) {
javaHome = Paths.get(System.getProperty("java.home"));
systemJavaHome = Locations.javaHome;
} else if (value.equals("none")) {
javaHome = null;
systemJavaHome = null;
} else {
update(Paths.get(value));
update(getPath(value));
}
modules = null;
@ -1360,13 +1371,13 @@ public class Locations {
@Override
Collection<Path> getPaths() {
return (javaHome == null) ? null : Collections.singleton(javaHome);
return (systemJavaHome == null) ? null : Collections.singleton(systemJavaHome);
}
@Override
void setPaths(Iterable<? extends Path> files) throws IOException {
if (files == null) {
javaHome = null;
systemJavaHome = null;
} else {
Iterator<? extends Path> pathIter = files.iterator();
if (!pathIter.hasNext()) {
@ -1386,16 +1397,15 @@ public class Locations {
}
private void update(Path p) {
if (!isCurrentPlatform(p) && !Files.exists(p.resolve("jrt-fs.jar")) && !Files.exists(javaHome.resolve("modules")))
if (!isCurrentPlatform(p) && !Files.exists(p.resolve("jrt-fs.jar")) && !Files.exists(systemJavaHome.resolve("modules")))
throw new IllegalArgumentException(p.toString());
javaHome = p;
systemJavaHome = p;
modules = null;
}
private boolean isCurrentPlatform(Path p) {
Path jh = Paths.get(System.getProperty("java.home"));
try {
return Files.isSameFile(p, jh);
return Files.isSameFile(p, Locations.javaHome);
} catch (IOException ex) {
throw new IllegalArgumentException(p.toString(), ex);
}
@ -1421,7 +1431,7 @@ public class Locations {
return;
}
if (javaHome == null) {
if (systemJavaHome == null) {
systemModules = Collections.emptyMap();
return;
}
@ -1431,15 +1441,15 @@ public class Locations {
URI jrtURI = URI.create("jrt:/");
FileSystem jrtfs;
if (isCurrentPlatform(javaHome)) {
if (isCurrentPlatform(systemJavaHome)) {
jrtfs = FileSystems.getFileSystem(jrtURI);
} else {
try {
Map<String, String> attrMap =
Collections.singletonMap("java.home", javaHome.toString());
Collections.singletonMap("java.home", systemJavaHome.toString());
jrtfs = FileSystems.newFileSystem(jrtURI, attrMap);
} catch (ProviderNotFoundException ex) {
URL javaHomeURL = javaHome.resolve("jrt-fs.jar").toUri().toURL();
URL javaHomeURL = systemJavaHome.resolve("jrt-fs.jar").toUri().toURL();
ClassLoader currentLoader = Locations.class.getClassLoader();
URLClassLoader fsLoader =
new URLClassLoader(new URL[] {javaHomeURL}, currentLoader);
@ -1454,7 +1464,7 @@ public class Locations {
modules = jrtfs.getPath("/modules");
} catch (FileSystemNotFoundException | ProviderNotFoundException e) {
modules = javaHome.resolve("modules");
modules = systemJavaHome.resolve("modules");
if (!Files.exists(modules))
throw new IOException("can't find system classes", e);
}

@ -109,7 +109,7 @@ public abstract class PathFileObject implements JavaFileObject {
private DirectoryFileObject(BaseFileManager fileManager, Path path,
Path userPackageRootDir, RelativePath relativePath) {
super(fileManager, path);
this.userPackageRootDir = userPackageRootDir;
this.userPackageRootDir = Objects.requireNonNull(userPackageRootDir);
this.relativePath = relativePath;
}

@ -26,10 +26,8 @@
package com.sun.tools.javac.file;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
@ -58,13 +56,8 @@ public abstract class RelativePath implements Comparable<RelativePath> {
public abstract String basename();
public Path resolveAgainst(Path directory) throws /*unchecked*/ InvalidPathException {
if (directory == null) {
String sep = FileSystems.getDefault().getSeparator();
return Paths.get(path.replace("/", sep));
} else {
String sep = directory.getFileSystem().getSeparator();
return directory.resolve(path.replace("/", sep));
}
String sep = directory.getFileSystem().getSeparator();
return directory.resolve(path.replace("/", sep));
}
public Path resolveAgainst(FileSystem fs) throws /*unchecked*/ InvalidPathException {

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -1045,7 +1045,7 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis {
public SourceCache(AnalyzeTask originalTask) {
this.originalTask = originalTask;
Iterable<? extends Path> sources = findSources();
List<Path> sources = findSources();
if (sources.iterator().hasNext()) {
StandardJavaFileManager fm = compiler.getStandardFileManager(null, null, null);
try {
@ -1145,9 +1145,9 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis {
}
}
private Iterable<? extends Path> availableSources;
private List<Path> availableSources;
private Iterable<? extends Path> findSources() {
private List<Path> findSources() {
if (availableSources != null) {
return availableSources;
}