This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-io.git


The following commit(s) were added to refs/heads/master by this push:
     new 1a8fcd01 [IO-811] Files.walk() direct and indirect callers fail to 
close the returned Stream<Path>
1a8fcd01 is described below

commit 1a8fcd01226b7cd547f0e9897d217ef381a94e64
Author: Gary Gregory <garydgreg...@gmail.com>
AuthorDate: Sat Sep 30 08:34:16 2023 -0400

    [IO-811] Files.walk() direct and indirect callers fail to close the
    returned Stream<Path>
    
    - Update Javadoc
    - Release resource in test
---
 src/main/java/org/apache/commons/io/FileUtils.java | 12 +++--
 .../org/apache/commons/io/file/FilesUncheck.java   | 60 +++++++++++++++++-----
 .../java/org/apache/commons/io/file/PathUtils.java | 11 +++-
 .../apache/commons/io/file/FilesUncheckTest.java   |  5 +-
 4 files changed, 70 insertions(+), 18 deletions(-)

diff --git a/src/main/java/org/apache/commons/io/FileUtils.java 
b/src/main/java/org/apache/commons/io/FileUtils.java
index 46275c5f..8a8adca7 100644
--- a/src/main/java/org/apache/commons/io/FileUtils.java
+++ b/src/main/java/org/apache/commons/io/FileUtils.java
@@ -36,6 +36,7 @@ import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
 import java.nio.charset.UnsupportedCharsetException;
 import java.nio.file.CopyOption;
+import java.nio.file.DirectoryStream;
 import java.nio.file.FileVisitOption;
 import java.nio.file.FileVisitResult;
 import java.nio.file.Files;
@@ -2960,13 +2961,16 @@ public class FileUtils {
     }
 
     /**
-     * Streams over the files in a given directory (and optionally
-     * its subdirectories) which match an array of extensions.
+     * Streams over the files in a given directory (and optionally its 
subdirectories) which match an array of extensions.
+     * <p>
+     * The returned {@link Stream} may wrap one or more {@link 
DirectoryStream}s. When you require timely disposal of file system resources, 
use a
+     * {@code try}-with-resources block to ensure invocation of the stream's 
{@link Stream#close()} method after the stream operations are completed. 
Calling a
+     * closed stream causes a {@link IllegalStateException}.
+     * </p>
      *
      * @param directory  the directory to search in
      * @param recursive  if true all subdirectories are searched as well
-     * @param extensions an array of extensions, ex. {"java","xml"}. If this
-     *                   parameter is {@code null}, all files are returned.
+     * @param extensions an array of extensions, ex. {"java","xml"}. If this 
parameter is {@code null}, all files are returned.
      * @return an iterator of java.io.File with the matching files
      * @throws IOException if an I/O error is thrown when accessing the 
starting file.
      * @since 2.9.0
diff --git a/src/main/java/org/apache/commons/io/file/FilesUncheck.java 
b/src/main/java/org/apache/commons/io/file/FilesUncheck.java
index 02a1febb..02688cac 100644
--- a/src/main/java/org/apache/commons/io/file/FilesUncheck.java
+++ b/src/main/java/org/apache/commons/io/file/FilesUncheck.java
@@ -22,6 +22,7 @@ import java.io.BufferedWriter;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.io.Reader;
 import java.io.UncheckedIOException;
 import java.nio.channels.SeekableByteChannel;
 import java.nio.charset.Charset;
@@ -244,6 +245,10 @@ public final class FilesUncheck {
 
     /**
      * Delegates to {@link Files#find(Path, int, BiPredicate, 
FileVisitOption...)} throwing {@link UncheckedIOException} instead of {@link 
IOException}.
+     * <p>
+     * The returned {@link Stream} wraps a {@link DirectoryStream}. When you 
require timely disposal of file system resources, use a {@code 
try}-with-resources
+     * block to ensure invocation of the stream's {@link Stream#close()} 
method after the stream operations are completed.
+     * </p>
      *
      * @param start    See delegate.
      * @param maxDepth See delegate.
@@ -348,6 +353,10 @@ public final class FilesUncheck {
 
     /**
      * Delegates to {@link Files#lines(Path)} throwing {@link 
UncheckedIOException} instead of {@link IOException}.
+     * <p>
+     * The returned {@link Stream} wraps a {@link Reader}. When you require 
timely disposal of file system resources, use a {@code try}-with-resources 
block to
+     * ensure invocation of the stream's {@link Stream#close()} method after 
the stream operations are completed.
+     * </p>
      *
      * @param path See delegate.
      * @return See delegate.
@@ -359,6 +368,10 @@ public final class FilesUncheck {
 
     /**
      * Delegates to {@link Files#lines(Path, Charset)} throwing {@link 
UncheckedIOException} instead of {@link IOException}.
+     * <p>
+     * The returned {@link Stream} wraps a {@link Reader}. When you require 
timely disposal of file system resources, use a {@code try}-with-resources 
block to
+     * ensure invocation of the stream's {@link Stream#close()} method after 
the stream operations are completed.
+     * </p>
      *
      * @param path See delegate.
      * @param cs See delegate.
@@ -371,6 +384,10 @@ public final class FilesUncheck {
 
     /**
      * Delegates to {@link Files#list(Path)} throwing {@link 
UncheckedIOException} instead of {@link IOException}.
+     * <p>
+     * The returned {@link Stream} wraps a {@link DirectoryStream}. When you 
require timely disposal of file system resources, use a {@code 
try}-with-resources
+     * block to ensure invocation of the stream's {@link Stream#close()} 
method after the stream operations are completed.
+     * </p>
      *
      * @param dir See delegate.
      * @return See delegate.
@@ -474,8 +491,11 @@ public final class FilesUncheck {
     }
 
     /**
-     * Delegates to {@link Files#newDirectoryStream(Path)} throwing {@link 
UncheckedIOException} instead of
-     * {@link IOException}.
+     * Delegates to {@link Files#newDirectoryStream(Path)} throwing {@link 
UncheckedIOException} instead of {@link IOException}.
+     * <p>
+     * If you don't use the try-with-resources construct, then you must call 
the stream's {@link Stream#close()} method after iteration is complete to free 
any
+     * resources held for the open directory.
+     * </p>
      *
      * @param dir See delegate.
      * @return See delegate.
@@ -485,10 +505,14 @@ public final class FilesUncheck {
     }
 
     /**
-     * Delegates to {@link Files#newDirectoryStream(Path, 
java.nio.file.DirectoryStream.Filter)} throwing
-     * {@link UncheckedIOException} instead of {@link IOException}.
+     * Delegates to {@link Files#newDirectoryStream(Path, 
java.nio.file.DirectoryStream.Filter)} throwing {@link UncheckedIOException} 
instead of
+     * {@link IOException}.
+     * <p>
+     * If you don't use the try-with-resources construct, then you must call 
the stream's {@link Stream#close()} method after iteration is complete to free 
any
+     * resources held for the open directory.
+     * </p>
      *
-     * @param dir See delegate.
+     * @param dir    See delegate.
      * @param filter See delegate.
      * @return See delegate.
      */
@@ -499,6 +523,10 @@ public final class FilesUncheck {
     /**
      * Delegates to {@link Files#newDirectoryStream(Path, String)} throwing 
{@link UncheckedIOException} instead of
      * {@link IOException}.
+     * <p>
+     * The returned {@link Stream} wraps a {@link DirectoryStream}. When you 
require timely disposal of file system resources, use a {@code 
try}-with-resources
+     * block to ensure invocation of the stream's {@link Stream#close()} 
method after the stream operations are completed.
+     * </p>
      *
      * @param dir See delegate.
      * @param glob See delegate.
@@ -674,10 +702,14 @@ public final class FilesUncheck {
     }
 
     /**
-     * Delegates to {@link Files#walk(Path, FileVisitOption...)} throwing 
{@link UncheckedIOException} instead of
-     * {@link IOException}.
+     * Delegates to {@link Files#walk(Path, FileVisitOption...)} throwing 
{@link UncheckedIOException} instead of {@link IOException}.
+     * <p>
+     * The returned {@link Stream} may wrap one or more {@link 
DirectoryStream}s. When you require timely disposal of file system resources, 
use a
+     * {@code try}-with-resources block to ensure invocation of the stream's 
{@link Stream#close()} method after the stream operations are completed. 
Calling a
+     * closed stream causes a {@link IllegalStateException}.
+     * </p>
      *
-     * @param start See delegate.
+     * @param start   See delegate.
      * @param options See delegate.
      * @return See delegate.
      */
@@ -686,12 +718,16 @@ public final class FilesUncheck {
     }
 
     /**
-     * Delegates to {@link Files#walk(Path, int, FileVisitOption...)} throwing 
{@link UncheckedIOException} instead of
-     * {@link IOException}.
+     * Delegates to {@link Files#walk(Path, int, FileVisitOption...)} throwing 
{@link UncheckedIOException} instead of {@link IOException}.
+     * <p>
+     * The returned {@link Stream} may wrap one or more {@link 
DirectoryStream}s. When you require timely disposal of file system resources, 
use a
+     * {@code try}-with-resources block to ensure invocation of the stream's 
{@link Stream#close()} method after the stream operations are completed. 
Calling a
+     * closed stream causes a {@link IllegalStateException}.
+     * </p>
      *
-     * @param start See delegate.
+     * @param start    See delegate.
      * @param maxDepth See delegate.
-     * @param options See delegate.
+     * @param options  See delegate.
      * @return See delegate.
      */
     public static Stream<Path> walk(final Path start, final int maxDepth, 
final FileVisitOption... options) {
diff --git a/src/main/java/org/apache/commons/io/file/PathUtils.java 
b/src/main/java/org/apache/commons/io/file/PathUtils.java
index 56b2a05c..3cd85f08 100644
--- a/src/main/java/org/apache/commons/io/file/PathUtils.java
+++ b/src/main/java/org/apache/commons/io/file/PathUtils.java
@@ -1182,8 +1182,12 @@ public final class PathUtils {
 
     /**
      * Creates a new DirectoryStream for Paths rooted at the given directory.
+     * <p>
+     * If you don't use the try-with-resources construct, then you must call 
the stream's {@link Stream#close()} method after iteration is complete to free 
any
+     * resources held for the open directory.
+     * </p>
      *
-     * @param dir the path to the directory to stream.
+     * @param dir        the path to the directory to stream.
      * @param pathFilter the directory stream filter.
      * @return a new instance.
      * @throws IOException if an I/O error occurs.
@@ -1751,6 +1755,11 @@ public final class PathUtils {
 
     /**
      * Returns a stream of filtered paths.
+     * <p>
+     * The returned {@link Stream} may wrap one or more {@link 
DirectoryStream}s. When you require timely disposal of file system resources, 
use a
+     * {@code try}-with-resources block to ensure invocation of the stream's 
{@link Stream#close()} method after the stream operations are completed. 
Calling a
+     * closed stream causes a {@link IllegalStateException}.
+     * </p>
      *
      * @param start the start path
      * @param pathFilter the path filter
diff --git a/src/test/java/org/apache/commons/io/file/FilesUncheckTest.java 
b/src/test/java/org/apache/commons/io/file/FilesUncheckTest.java
index 4fa73681..917de24f 100644
--- a/src/test/java/org/apache/commons/io/file/FilesUncheckTest.java
+++ b/src/test/java/org/apache/commons/io/file/FilesUncheckTest.java
@@ -50,6 +50,7 @@ import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.Set;
+import java.util.stream.Stream;
 
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.io.function.Uncheck;
@@ -166,7 +167,9 @@ public class FilesUncheckTest {
 
     @Test
     public void testFind() {
-        assertNotNull(FilesUncheck.find(FILE_PATH_EMPTY, 0, (t, u) -> false));
+        try (Stream<Path> find = FilesUncheck.find(FILE_PATH_EMPTY, 0, (t, u) 
-> false)) {
+            assertNotNull(find);
+        }
     }
 
     @Test

Reply via email to