Summary
Add a new method StandardJavaFileManager#getJavaFileObjectsFromPaths(Collection<? extends Path>)
and deprecate getJavaFileObjectsFromPaths(Iterable<? extends Path>)
with a migration path to the new method.
Problem
Using StandardJavaFileManager#getJavaFileObjectsFromPaths(Iterable<? extends Path>)
is error-prone, since Path
itself implements Iterable<Path>
. This allows accidentally passing a single path when the intent was to pass a singleton collection, i.e.: getJavaFileObjectsFromPaths(path)
vs. getJavaFileObjectsFromPaths(List.of(Path))
.
Solution
The solution is to add a new method that accepts a Collection<? extends Path>
, which cannot be confused with an individual Path
. The existing Iterable
-accepting method is deprecated, and its default implementation delegates to the new method for migration compatibility.
A similar issue affected setLocationFromPaths
, but was fixed before that method was released in JDK 9; see JDK-8150111.
Specification
The javadoc specification for the new method is identical to previous iterable-accepting version. (The @param
javadoc refers informally to a 'list of paths' and does not need updating.)
diff -r eed9f74eab87 src/java.compiler/share/classes/javax/tools/StandardJavaFileManager.java
--- a/src/java.compiler/share/classes/javax/tools/StandardJavaFileManager.java Fri Mar 15 09:57:42 2019 +0100
+++ b/src/java.compiler/share/classes/javax/tools/StandardJavaFileManager.java Thu Mar 21 20:08:52 2019 -0700
@@ -28,9 +28,11 @@
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
+import java.util.List;
/**
* File manager based on {@linkplain File java.io.File} and {@linkplain Path java.nio.file.Path}.
@@ -199,11 +201,40 @@
* a directory or if this file manager does not support any of the
* given paths.
*
- * @since 9
+ * @since 13
*/
default Iterable<? extends JavaFileObject> getJavaFileObjectsFromPaths(
+ Collection<? extends Path> paths) {
+ return getJavaFileObjectsFromFiles(asFiles(paths));
+ }
+
+ /**
+ * Returns file objects representing the given paths.
+ *
+ * @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.
+ *
+ * @param paths a list of paths
+ * @return a list of file objects
+ * @throws IllegalArgumentException if the list of paths includes
+ * a directory or if this file manager does not support any of the
+ * given paths.
+ *
+ * @since 9
+ * @deprecated use {@link #getJavaFileObjectsFromPaths(Collection)} instead,
+ * to prevent the possibility of accidentally calling the method with a
+ * single {@code Path} as such an argument. Although {@code Path} implements
+ * {@code Iterable<Path>}, it would almost never be correct to pass a single
+ * {@code Path} and have it be treated as an {@code Iterable} of its
+ * components.
+ */
+ @Deprecated(since = "13")
+ default Iterable<? extends JavaFileObject> getJavaFileObjectsFromPaths(
Iterable<? extends Path> paths) {
- return getJavaFileObjectsFromFiles(asFiles(paths));
+ return getJavaFileObjectsFromPaths(asCollection(paths));
}
/**
@@ -484,4 +515,13 @@
}
};
}
+
+ private static <T> Collection<T> asCollection(Iterable<T> iterable) {
+ if (iterable instanceof Collection) {
+ return (Collection<T>) iterable;
+ }
+ List<T> result = new ArrayList<>();
+ for (T item : iterable) result.add(item);
+ return result;
+ }
}
- csr of
-
JDK-8220687 Add StandardJavaFileManager.getJavaFileObjectsFromPaths overload
-
- Resolved
-