Skip to content

Commit 68be2fb

Browse files
authored
Add and use IOUtils.closeQuietly(Closeable, Throwable) (#818)
* [IO-856] Try test on all OSs for GitHub CI * Add and use IOUtils.closeQuietly(Closeable, Throwable)
1 parent 8f66b32 commit 68be2fb

File tree

5 files changed

+51
-10
lines changed

5 files changed

+51
-10
lines changed

src/main/java/org/apache/commons/io/FileUtils.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2290,7 +2290,7 @@ public static LineIterator lineIterator(final File file, final String charsetNam
22902290
inputStream = Files.newInputStream(file.toPath());
22912291
return IOUtils.lineIterator(inputStream, charsetName);
22922292
} catch (final IOException | RuntimeException ex) {
2293-
IOUtils.closeQuietly(inputStream, ex::addSuppressed);
2293+
IOUtils.closeQuietly(inputStream, ex);
22942294
throw ex;
22952295
}
22962296
}

src/main/java/org/apache/commons/io/IOUtils.java

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -780,7 +780,7 @@ public static void close(final URLConnection conn) {
780780
* @param closeable the object to close, may be null.
781781
*/
782782
private static void closeQ(final Closeable closeable) {
783-
closeQuietly(closeable, null);
783+
closeQuietly(closeable, (Consumer<Exception>) null);
784784
}
785785

786786
/**
@@ -824,7 +824,40 @@ private static void closeQ(final Closeable closeable) {
824824
* @see Throwable#addSuppressed(Throwable)
825825
*/
826826
public static void closeQuietly(final Closeable closeable) {
827-
closeQuietly(closeable, null);
827+
closeQuietly(closeable, (Consumer<Exception>) null);
828+
}
829+
830+
/**
831+
* Closes a {@link Closeable} unconditionally and adds any exception thrown by the {@code close()} to the given Throwable.
832+
*
833+
* <p>
834+
* For example:
835+
* </p>
836+
*
837+
* <pre>
838+
* Closeable closeable = ...;
839+
* try {
840+
* // process closeable
841+
* closeable.close();
842+
* } catch (Exception e) {
843+
* // error handling
844+
* throw IOUtils.closeQuietly(closeable, e);
845+
* }
846+
* </pre>
847+
* <p>
848+
* Also consider using a try-with-resources statement where appropriate.
849+
* </p>
850+
*
851+
* @param <T> The Throwable type.
852+
* @param closeable The object to close, may be null or already closed.
853+
* @param throwable Add the exception throw by the closeable to the given Throwable.
854+
* @return The given Throwable.
855+
* @since 2.22.0
856+
* @see Throwable#addSuppressed(Throwable)
857+
*/
858+
public static <T extends Throwable> T closeQuietly(final Closeable closeable, final T throwable) {
859+
closeQuietly(closeable, (Consumer<Exception>) throwable::addSuppressed);
860+
return throwable;
828861
}
829862

830863
/**

src/main/java/org/apache/commons/io/LineIterator.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,7 @@ public boolean hasNext() {
135135
}
136136
}
137137
} catch (final IOException ioe) {
138-
IOUtils.closeQuietly(this, ioe::addSuppressed);
139-
throw new IllegalStateException(ioe);
138+
throw new IllegalStateException(IOUtils.closeQuietly(this, ioe));
140139
}
141140
}
142141

src/main/java/org/apache/commons/io/output/FileWriterWithEncoding.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -188,11 +188,7 @@ private static OutputStreamWriter initWriter(final File file, final Object encod
188188
}
189189
return new OutputStreamWriter(outputStream, (String) encoding);
190190
} catch (final IOException | RuntimeException ex) {
191-
try {
192-
IOUtils.close(outputStream);
193-
} catch (final IOException e) {
194-
ex.addSuppressed(e);
195-
}
191+
IOUtils.closeQuietly(outputStream, ex);
196192
if (!fileExistedAlready) {
197193
FileUtils.deleteQuietly(file);
198194
}

src/test/java/org/apache/commons/io/IOUtilsTest.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
2121
import static org.junit.jupiter.api.Assertions.assertEquals;
2222
import static org.junit.jupiter.api.Assertions.assertFalse;
23+
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
2324
import static org.junit.jupiter.api.Assertions.assertNotNull;
2425
import static org.junit.jupiter.api.Assertions.assertNotSame;
2526
import static org.junit.jupiter.api.Assertions.assertNull;
@@ -539,6 +540,18 @@ void testCloseQuietly_AllCloseableIOException() {
539540
assertDoesNotThrow(() -> IOUtils.closeQuietly((Iterable<Closeable>) null));
540541
}
541542

543+
@SuppressWarnings("resource")
544+
@Test
545+
void testCloseQuietly_CloseableIOExceptionAddSuppressed() {
546+
final Throwable e = new Exception("test").fillInStackTrace();
547+
assertEquals(0, e.getSuppressed().length);
548+
assertSame(e, IOUtils.closeQuietly(new BrokenInputStream(new EOFException("Suppressed").fillInStackTrace()), e));
549+
assertEquals(1, e.getSuppressed().length);
550+
final Throwable suppressed0 = e.getSuppressed()[0];
551+
assertInstanceOf(EOFException.class, suppressed0);
552+
assertEquals("Suppressed", suppressed0.getMessage());
553+
}
554+
542555
@Test
543556
void testCloseQuietly_CloseableException() {
544557
// IOException

0 commit comments

Comments
 (0)