Skip to content

Commit 6b0ed87

Browse files
committed
[IO-826] Add BrokenInputStream.BrokenInputStream(RuntimeException)
Make public Erase.rethrow(Throwable)
1 parent 9bcaf43 commit 6b0ed87

4 files changed

Lines changed: 107 additions & 37 deletions

File tree

src/changes/changes.xml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,10 @@ The <action> type attribute can be add,update,fix,remove.
5757
<action dev="ggregory" type="fix" issue="IO-781" due-to="Elliotte Rusty Harold">Make CharSequenceInputStream.available() more correct in the face of multibyte encodings #525.</action>
5858
<action dev="ggregory" type="fix" issue="IO-781" due-to="Elliotte Rusty Harold">Remove unreachable code in AbstractIOFileFilterTest #526.</action>
5959
<!-- Add -->
60-
<action dev="ggregory" type="fix" issue="IO-825" due-to="dkdal, Gary Gregory">Add and use PathUtils.getFileName(Path, Function&lt;Path, R&gt;).</action>
61-
<action dev="ggregory" type="fix" issue="IO-825" due-to="dkdal, Gary Gregory">Add and use PathUtils.getFileNameString().</action>
60+
<action dev="ggregory" type="fix" due-to="Gary Gregory">Add and use PathUtils.getFileName(Path, Function&lt;Path, R&gt;).</action>
61+
<action dev="ggregory" type="fix" due-to="Gary Gregory">Add and use PathUtils.getFileNameString().</action>
62+
<action dev="ggregory" type="fix" due-to="Gary Gregory">Make public Erase.rethrow(Throwable).</action>
63+
<action dev="ggregory" type="fix" issue="IO-826" due-to="markslater, Gary Gregory">Add BrokenInputStream.BrokenInputStream(Throwable).</action>
6264
</release>
6365
<release version="2.15.1" date="2023-11-24" description="Java 8 is required.">
6466
<!-- FIX -->

src/main/java/org/apache/commons/io/function/Erase.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@
2020

2121
/**
2222
* Erases {@link IOException} for the compiler but still throws that exception at runtime.
23+
*
24+
* @since 2.16.0
2325
*/
24-
final class Erase {
26+
public final class Erase {
2527

2628
/**
2729
* Delegates to the given {@link IOBiConsumer} but erases its {@link IOException} for the compiler, while still throwing
@@ -144,7 +146,7 @@ static <T> T get(final IOSupplier<T> supplier) {
144146
* @throws T Always thrown.
145147
*/
146148
@SuppressWarnings("unchecked")
147-
static <T extends Throwable> RuntimeException rethrow(final Throwable throwable) throws T {
149+
public static <T extends Throwable> RuntimeException rethrow(final Throwable throwable) throws T {
148150
throw (T) throwable;
149151
}
150152

src/main/java/org/apache/commons/io/input/BrokenInputStream.java

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
import java.io.InputStream;
2121
import java.util.function.Supplier;
2222

23+
import org.apache.commons.io.function.Erase;
24+
2325
/**
2426
* Always throws an {@link IOException} from all the {@link InputStream} methods where the exception is declared.
2527
* <p>
@@ -40,7 +42,7 @@ public class BrokenInputStream extends InputStream {
4042
/**
4143
* A supplier for the exception that is thrown by all methods of this class.
4244
*/
43-
private final Supplier<IOException> exceptionSupplier;
45+
private final Supplier<Throwable> exceptionSupplier;
4446

4547
/**
4648
* Constructs a new stream that always throws an {@link IOException}.
@@ -53,18 +55,30 @@ public BrokenInputStream() {
5355
* Constructs a new stream that always throws the given exception.
5456
*
5557
* @param exception the exception to be thrown.
58+
* @deprecated Use {@link #BrokenInputStream(Throwable)}.
5659
*/
60+
@Deprecated
5761
public BrokenInputStream(final IOException exception) {
5862
this(() -> exception);
5963
}
6064

65+
/**
66+
* Constructs a new stream that always throws the given exception.
67+
*
68+
* @param exception the exception to be thrown.
69+
* @since 2.16.0
70+
*/
71+
public BrokenInputStream(final Throwable exception) {
72+
this(() -> exception);
73+
}
74+
6175
/**
6276
* Constructs a new stream that always throws an {@link IOException}.
6377
*
64-
* @param exceptionSupplier a supplier for the exception to be thrown.
78+
* @param exceptionSupplier a supplier for the IOException or RuntimeException to be thrown.
6579
* @since 2.12.0
6680
*/
67-
public BrokenInputStream(final Supplier<IOException> exceptionSupplier) {
81+
public BrokenInputStream(final Supplier<Throwable> exceptionSupplier) {
6882
this.exceptionSupplier = exceptionSupplier;
6983
}
7084

@@ -76,7 +90,7 @@ public BrokenInputStream(final Supplier<IOException> exceptionSupplier) {
7690
*/
7791
@Override
7892
public int available() throws IOException {
79-
throw exceptionSupplier.get();
93+
throw rethrow();
8094
}
8195

8296
/**
@@ -86,7 +100,7 @@ public int available() throws IOException {
86100
*/
87101
@Override
88102
public void close() throws IOException {
89-
throw exceptionSupplier.get();
103+
throw rethrow();
90104
}
91105

92106
/**
@@ -97,7 +111,7 @@ public void close() throws IOException {
97111
*/
98112
@Override
99113
public int read() throws IOException {
100-
throw exceptionSupplier.get();
114+
throw rethrow();
101115
}
102116

103117
/**
@@ -107,7 +121,16 @@ public int read() throws IOException {
107121
*/
108122
@Override
109123
public synchronized void reset() throws IOException {
110-
throw exceptionSupplier.get();
124+
throw rethrow();
125+
}
126+
127+
/**
128+
* Throws the configured exception from its supplier.
129+
*
130+
* @return Throws the configured exception from its supplier.
131+
*/
132+
private RuntimeException rethrow() {
133+
return Erase.rethrow(exceptionSupplier.get());
111134
}
112135

113136
/**
@@ -119,7 +142,7 @@ public synchronized void reset() throws IOException {
119142
*/
120143
@Override
121144
public long skip(final long n) throws IOException {
122-
throw exceptionSupplier.get();
145+
throw rethrow();
123146
}
124147

125148
}

src/test/java/org/apache/commons/io/input/BrokenInputStreamTest.java

Lines changed: 68 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -19,56 +19,99 @@
1919
import static org.junit.jupiter.api.Assertions.assertEquals;
2020
import static org.junit.jupiter.api.Assertions.assertThrows;
2121

22+
import java.io.FileNotFoundException;
2223
import java.io.IOException;
2324
import java.io.InputStream;
25+
import java.nio.file.FileSystemNotFoundException;
26+
import java.util.stream.Stream;
2427

25-
import org.junit.jupiter.api.BeforeEach;
2628
import org.junit.jupiter.api.Test;
29+
import org.junit.jupiter.params.ParameterizedTest;
30+
import org.junit.jupiter.params.provider.MethodSource;
2731

2832
/**
2933
* Tests {@link BrokenInputStream}.
3034
*/
3135
public class BrokenInputStreamTest {
3236

33-
private IOException exception;
37+
static final class CustomeException extends Exception {
3438

35-
private InputStream stream;
39+
private static final long serialVersionUID = 1L;
3640

37-
@BeforeEach
38-
public void setUp() {
39-
exception = new IOException("test exception");
40-
stream = new BrokenInputStream(exception);
4141
}
4242

43-
@Test
44-
public void testAvailable() {
45-
assertEquals(exception, assertThrows(IOException.class, () -> stream.available()));
43+
static Stream<Class<? extends Throwable>> parameters() {
44+
// @formatter:off
45+
return Stream.of(
46+
IOException.class,
47+
FileNotFoundException.class,
48+
FileSystemNotFoundException.class,
49+
RuntimeException.class,
50+
IllegalArgumentException.class,
51+
IllegalStateException.class,
52+
Error.class,
53+
ExceptionInInitializerError.class,
54+
CustomeException.class
55+
);
56+
// @formatter:on
4657
}
4758

48-
@Test
49-
public void testClose() {
50-
assertEquals(exception, assertThrows(IOException.class, () -> stream.close()));
59+
private BrokenInputStream createBrokenInputStream(final Throwable exception) {
60+
if (exception instanceof IOException) {
61+
return new BrokenInputStream((IOException) exception);
62+
}
63+
return new BrokenInputStream(exception);
5164
}
5265

53-
@Test
54-
public void testRead() {
55-
assertEquals(exception, assertThrows(IOException.class, () -> stream.read()));
56-
assertEquals(exception, assertThrows(IOException.class, () -> stream.read(new byte[1])));
57-
assertEquals(exception, assertThrows(IOException.class, () -> stream.read(new byte[1], 0, 1)));
66+
@ParameterizedTest
67+
@MethodSource("parameters")
68+
public void testAvailable(final Class<Exception> clazz) throws Exception {
69+
final Throwable exception = clazz.newInstance();
70+
@SuppressWarnings("resource")
71+
final BrokenInputStream stream = createBrokenInputStream(exception);
72+
assertEquals(exception, assertThrows(exception.getClass(), () -> stream.available()));
5873
}
5974

60-
@Test
61-
public void testReset() {
62-
assertEquals(exception, assertThrows(IOException.class, () -> stream.reset()));
75+
@ParameterizedTest
76+
@MethodSource("parameters")
77+
public void testClose(final Class<Exception> clazz) throws Exception {
78+
final Throwable exception = clazz.newInstance();
79+
@SuppressWarnings("resource")
80+
final BrokenInputStream stream = createBrokenInputStream(exception);
81+
assertEquals(exception, assertThrows(exception.getClass(), () -> stream.close()));
6382
}
6483

65-
@Test
66-
public void testSkip() {
67-
assertEquals(exception, assertThrows(IOException.class, () -> stream.skip(1)));
84+
@ParameterizedTest
85+
@MethodSource("parameters")
86+
public void testRead(final Class<Exception> clazz) throws Exception {
87+
final Throwable exception = clazz.newInstance();
88+
@SuppressWarnings("resource")
89+
final BrokenInputStream stream = createBrokenInputStream(exception);
90+
assertEquals(exception, assertThrows(exception.getClass(), () -> stream.read()));
91+
assertEquals(exception, assertThrows(exception.getClass(), () -> stream.read(new byte[1])));
92+
assertEquals(exception, assertThrows(exception.getClass(), () -> stream.read(new byte[1], 0, 1)));
93+
}
94+
95+
@ParameterizedTest
96+
@MethodSource("parameters")
97+
public void testReset(final Class<Exception> clazz) throws Exception {
98+
final Throwable exception = clazz.newInstance();
99+
@SuppressWarnings("resource")
100+
final BrokenInputStream stream = createBrokenInputStream(exception);
101+
assertEquals(exception, assertThrows(exception.getClass(), () -> stream.reset()));
102+
}
103+
104+
@ParameterizedTest
105+
@MethodSource("parameters")
106+
public void testSkip(final Class<Exception> clazz) throws Exception {
107+
final Throwable exception = clazz.newInstance();
108+
@SuppressWarnings("resource")
109+
final BrokenInputStream stream = createBrokenInputStream(exception);
110+
assertEquals(exception, assertThrows(exception.getClass(), () -> stream.skip(1)));
68111
}
69112

70113
@Test
71-
public void testTryWithResources() {
114+
public void testTryWithResources() throws Exception {
72115
final IOException thrown = assertThrows(IOException.class, () -> {
73116
try (InputStream newStream = new BrokenInputStream()) {
74117
newStream.read();

0 commit comments

Comments
 (0)