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 15ab5d465 AutoCloseInputStream does not call handleIOException() on close() 15ab5d465 is described below commit 15ab5d4658a5bfd2b7152563b99113ad5c46d885 Author: Gary Gregory <garydgreg...@gmail.com> AuthorDate: Sun Jul 14 09:23:51 2024 -0400 AutoCloseInputStream does not call handleIOException() on close() --- src/changes/changes.xml | 1 + .../commons/io/input/AutoCloseInputStream.java | 2 +- .../apache/commons/io/input/ProxyInputStream.java | 24 ++++++++++++++++++++-- .../commons/io/input/AutoCloseInputStreamTest.java | 19 ++++++++++++++++- 4 files changed, 42 insertions(+), 4 deletions(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index d6d8af038..14c59ec57 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -83,6 +83,7 @@ The <action> type attribute can be add,update,fix,remove. <action dev="ggregory" type="fix" due-to="Gary Gregory">RandomAccessFileInputStream.read() should return -1 (EOF) after the stream is closed.</action> <action dev="ggregory" type="fix" due-to="Gary Gregory">ReaderInputStream.available() should return 0 after the stream is closed.</action> <action dev="ggregory" type="fix" due-to="Gary Gregory">ReaderInputStream.read() should return -1 (EOF) after the stream is closed.</action> + <action dev="ggregory" type="fix" due-to="Gary Gregory">AutoCloseInputStream does not call handleIOException() on close().</action> <!-- UPDATE --> <action dev="ggregory" type="update" due-to="Dependabot">Bump tests commons.bytebuddy.version from 1.14.13 to 1.14.18 #615, #621, #631, #635, #642.</action> <action dev="ggregory" type="update" due-to="Dependabot">Bump tests commons-codec:commons-codec from 1.16.1 to 1.17.0.</action> diff --git a/src/main/java/org/apache/commons/io/input/AutoCloseInputStream.java b/src/main/java/org/apache/commons/io/input/AutoCloseInputStream.java index df6da7795..16276f909 100644 --- a/src/main/java/org/apache/commons/io/input/AutoCloseInputStream.java +++ b/src/main/java/org/apache/commons/io/input/AutoCloseInputStream.java @@ -140,7 +140,7 @@ public class AutoCloseInputStream extends ProxyInputStream { */ @Override public void close() throws IOException { - in.close(); + super.close(); in = ClosedInputStream.INSTANCE; } diff --git a/src/main/java/org/apache/commons/io/input/ProxyInputStream.java b/src/main/java/org/apache/commons/io/input/ProxyInputStream.java index 1a974ce6c..392173ae7 100644 --- a/src/main/java/org/apache/commons/io/input/ProxyInputStream.java +++ b/src/main/java/org/apache/commons/io/input/ProxyInputStream.java @@ -23,6 +23,7 @@ import java.io.IOException; import java.io.InputStream; import org.apache.commons.io.IOUtils; +import org.apache.commons.io.function.IOConsumer; /** * A proxy stream which acts as a {@link FilterInputStream}, by passing all method calls on to the proxied stream, not changing which methods are called. @@ -47,14 +48,33 @@ public abstract class ProxyInputStream extends FilterInputStream { */ private boolean closed; + /** + * Handles exceptions. + */ + private final IOConsumer<IOException> exceptionHandler; + /** * Constructs a new ProxyInputStream. * - * @param proxy the InputStream to delegate to + * @param proxy the InputStream to proxy. */ public ProxyInputStream(final InputStream proxy) { + // the proxy is stored in a protected superclass variable named 'in' + this(proxy, e -> { + throw e; + }); + } + + /** + * Constructs a new ProxyInputStream for testing. + * + * @param proxy the InputStream to proxy. + * @param exceptionHandler the exception handler. + */ + ProxyInputStream(final InputStream proxy, final IOConsumer<IOException> exceptionHandler) { // the proxy is stored in a protected superclass variable named 'in' super(proxy); + this.exceptionHandler = exceptionHandler; } /** @@ -147,7 +167,7 @@ public abstract class ProxyInputStream extends FilterInputStream { * @since 2.0 */ protected void handleIOException(final IOException e) throws IOException { - throw e; + exceptionHandler.accept(e); } /** diff --git a/src/test/java/org/apache/commons/io/input/AutoCloseInputStreamTest.java b/src/test/java/org/apache/commons/io/input/AutoCloseInputStreamTest.java index 341905ac4..b52e844a5 100644 --- a/src/test/java/org/apache/commons/io/input/AutoCloseInputStreamTest.java +++ b/src/test/java/org/apache/commons/io/input/AutoCloseInputStreamTest.java @@ -20,6 +20,8 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -46,7 +48,7 @@ public class AutoCloseInputStreamTest { data = new byte[] { 'x', 'y', 'z' }; stream = new AutoCloseInputStream(new ByteArrayInputStream(data) { @Override - public void close() { + public void close() throws IOException { closed = true; } }); @@ -90,7 +92,22 @@ public class AutoCloseInputStreamTest { public void testClose() throws IOException { stream.close(); assertTrue(closed, "closed"); + assertTrue(stream.isClosed(), "closed"); assertEquals(-1, stream.read(), "read()"); + assertTrue(stream.isClosed(), "closed"); + } + + @SuppressWarnings("resource") + @Test + public void testCloseHandleIOException() throws IOException { + final IOException exception = new IOException(); + @SuppressWarnings({ "deprecation" }) + final ProxyInputStream inputStream = AutoCloseInputStream.builder().setInputStream(new BrokenInputStream(exception)).get(); + assertFalse(inputStream.isClosed(), "closed"); + final ProxyInputStream spy = spy(inputStream); + assertThrows(IOException.class, spy::close); + verify(spy).handleIOException(exception); + assertFalse(spy.isClosed(), "closed"); } @Test