Skip to content

Commit 1a2cfc8

Browse files
committed
Avoid NullPointerException in ProxyInputStream.markSupported() when the
underlying input stream is null Javadoc
1 parent fb5e549 commit 1a2cfc8

4 files changed

Lines changed: 71 additions & 27 deletions

File tree

src/changes/changes.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ The <action> type attribute can be add,update,fix,remove.
6565
<action dev="ggregory" type="fix" due-to="Gary Gregory">PathUtils.isPosix(Path, LinkOption...) should return false on null input.</action>
6666
<action dev="ggregory" type="fix" due-to="Gary Gregory">AutoCloseInputStream(InputStream) uses ClosedInputStream.INSTANCE when its input is null.</action>
6767
<action dev="ggregory" type="fix" due-to="Gary Gregory">Avoid NullPointerException in ProxyInputStream.available() when the underlying input stream is null.</action>
68+
<action dev="ggregory" type="fix" due-to="Gary Gregory">Avoid NullPointerException in ProxyInputStream.markSupported() when the underlying input stream is null.</action>
6869
<action dev="ggregory" type="fix" due-to="Gary Gregory">BufferedFileChannelInputStream.available() returns 0 before any reads.</action>
6970
<action dev="ggregory" type="fix" due-to="Gary Gregory">BufferedFileChannelInputStream.available() should return 0 when the stream is closed instead of throwing an exception.</action>
7071
<action dev="ggregory" type="fix" due-to="Gary Gregory">CharSequenceInputStream.available() should return 0 after the stream is closed.</action>

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

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,9 @@ protected void afterRead(final int n) throws IOException {
102102
}
103103

104104
/**
105-
* Invokes the delegate's {@code available()} method.
105+
* Invokes the delegate's {@link InputStream#available()} method.
106106
*
107-
* @return the number of available bytes
107+
* @return the number of available bytes, 0 if the stream is closed.
108108
* @throws IOException if an I/O error occurs.
109109
*/
110110
@Override
@@ -145,7 +145,7 @@ protected void beforeRead(final int n) throws IOException {
145145
}
146146

147147
/**
148-
* Invokes the delegate's {@code close()} method.
148+
* Invokes the delegate's {@link InputStream#close()} method.
149149
*
150150
* @throws IOException if an I/O error occurs.
151151
*/
@@ -180,7 +180,7 @@ boolean isClosed() {
180180
}
181181

182182
/**
183-
* Invokes the delegate's {@code mark(int)} method.
183+
* Invokes the delegate's {@link InputStream#mark(int)} method.
184184
*
185185
* @param readLimit read ahead limit
186186
*/
@@ -190,17 +190,17 @@ public synchronized void mark(final int readLimit) {
190190
}
191191

192192
/**
193-
* Invokes the delegate's {@code markSupported()} method.
193+
* Invokes the delegate's {@link InputStream#markSupported()} method.
194194
*
195195
* @return true if mark is supported, otherwise false
196196
*/
197197
@Override
198198
public boolean markSupported() {
199-
return in.markSupported();
199+
return in != null && in.markSupported();
200200
}
201201

202202
/**
203-
* Invokes the delegate's {@code read()} method unless the stream is closed.
203+
* Invokes the delegate's {@link InputStream#read()} method unless the stream is closed.
204204
*
205205
* @return the byte read or -1 if the end of stream
206206
* @throws IOException if an I/O error occurs.
@@ -222,7 +222,7 @@ public int read() throws IOException {
222222
}
223223

224224
/**
225-
* Invokes the delegate's {@code read(byte[])} method.
225+
* Invokes the delegate's {@link InputStream#read(byte[])} method.
226226
*
227227
* @param b the buffer to read the bytes into
228228
* @return the number of bytes read or EOF if the end of stream
@@ -242,7 +242,7 @@ public int read(final byte[] b) throws IOException {
242242
}
243243

244244
/**
245-
* Invokes the delegate's {@code read(byte[], int, int)} method.
245+
* Invokes the delegate's {@link InputStream#read(byte[], int, int)} method.
246246
*
247247
* @param b the buffer to read the bytes into
248248
* @param off The start offset
@@ -264,7 +264,7 @@ public int read(final byte[] b, final int off, final int len) throws IOException
264264
}
265265

266266
/**
267-
* Invokes the delegate's {@code reset()} method.
267+
* Invokes the delegate's {@link InputStream#reset()} method.
268268
*
269269
* @throws IOException if an I/O error occurs.
270270
*/
@@ -278,7 +278,16 @@ public synchronized void reset() throws IOException {
278278
}
279279

280280
/**
281-
* Invokes the delegate's {@code skip(long)} method.
281+
* Package-private for testing.
282+
*
283+
* @param in The input stream to set.
284+
*/
285+
void setIn(final InputStream in) {
286+
this.in = in;
287+
}
288+
289+
/**
290+
* Invokes the delegate's {@link InputStream#skip(long)} method.
282291
*
283292
* @param n the number of bytes to skip
284293
* @return the actual number of bytes skipped

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

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
*
1111
* Unless required by applicable law or agreed to in writing, software
1212
* distributed under the License is distributed on an "AS IS" BASIS,
13-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* WITHOUProxyInputStreamFixture WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1414
* See the License for the specific language governing permissions and
1515
* limitations under the License.
1616
*/
@@ -20,6 +20,7 @@
2020
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
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.assertNotNull;
2324
import static org.junit.jupiter.api.Assertions.assertSame;
2425
import static org.junit.jupiter.api.Assertions.assertThrows;
2526
import static org.mockito.Mockito.spy;
@@ -47,10 +48,6 @@ private static final class ProxyInputStreamFixture extends ProxyInputStream {
4748
ProxyInputStreamFixture(final InputStream proxy) {
4849
super(proxy);
4950
}
50-
51-
void setIn(final InputStream proxy) {
52-
in = proxy;
53-
}
5451
}
5552

5653
@SuppressWarnings("resource")
@@ -69,12 +66,23 @@ static void testCloseHandleIOException(final ProxyInputStream inputStream) throw
6966
assertFalse(spy.isClosed(), "closed");
7067
}
7168

72-
@SuppressWarnings({ "resource", "unused" }) // For subclasses
69+
/**
70+
* Asserts that a ProxyInputStream's markSupported() equals the proxied value.
71+
*
72+
* @param inputStream The stream to test.
73+
*/
74+
@SuppressWarnings("resource") // unwrap() is a getter
75+
protected void assertMarkSupportedEquals(final ProxyInputStream inputStream) {
76+
assertNotNull(inputStream, "inputStream");
77+
assertEquals(inputStream.unwrap().markSupported(), inputStream.markSupported());
78+
}
79+
80+
@SuppressWarnings({ "resource", "unused", "unchecked" }) // For subclasses
7381
protected T createFixture() throws IOException {
74-
return (T) new ProxyInputStreamFixture(createProxySource());
82+
return (T) new ProxyInputStreamFixture(createOriginInputStream());
7583
}
7684

77-
protected InputStream createProxySource() {
85+
protected InputStream createOriginInputStream() {
7886
return CharSequenceInputStream.builder().setCharSequence("abc").get();
7987
}
8088

@@ -121,6 +129,32 @@ protected void testEos(final T inputStream) {
121129
// empty
122130
}
123131

132+
@Test
133+
public void testMarkSupported() throws IOException {
134+
try (T inputStream = createFixture()) {
135+
assertMarkSupportedEquals(inputStream);
136+
}
137+
}
138+
139+
@SuppressWarnings("resource")
140+
@Test
141+
public void testMarkSupportedAfterClose() throws IOException {
142+
final T shadow;
143+
try (T inputStream = createFixture()) {
144+
shadow = inputStream;
145+
}
146+
assertMarkSupportedEquals(shadow);
147+
}
148+
149+
@Test
150+
public void testMarkSupportedOnNull() throws IOException {
151+
try (ProxyInputStream fixture = createFixture()) {
152+
assertMarkSupportedEquals(fixture);
153+
fixture.setIn(null);
154+
assertFalse(fixture.markSupported());
155+
}
156+
}
157+
124158
@Test
125159
public void testRead() throws IOException {
126160
try (T inputStream = createFixture()) {
@@ -132,7 +166,7 @@ public void testRead() throws IOException {
132166
assertEquals('c', found);
133167
found = inputStream.read();
134168
assertEquals(-1, found);
135-
testEos(inputStream);
169+
testEos((T) inputStream);
136170
}
137171
}
138172

@@ -159,7 +193,7 @@ public void testReadArrayAtMiddleFully() throws IOException {
159193
assertArrayEquals(new byte[] { 0, 0, 'a', 'b', 'c' }, dest);
160194
found = inputStream.read(dest, 2, 3);
161195
assertEquals(-1, found);
162-
testEos(inputStream);
196+
testEos((T) inputStream);
163197
}
164198
}
165199

@@ -172,7 +206,7 @@ public void testReadArrayAtStartFully() throws IOException {
172206
assertArrayEquals(new byte[] { 'a', 'b', 'c', 0, 0 }, dest);
173207
found = inputStream.read(dest, 0, 5);
174208
assertEquals(-1, found);
175-
testEos(inputStream);
209+
testEos((T) inputStream);
176210
}
177211
}
178212

@@ -189,7 +223,7 @@ public void testReadArrayAtStartPartial() throws IOException {
189223
assertArrayEquals(new byte[] { 'c', 0, 0, 0, 0 }, dest);
190224
found = inputStream.read(dest, 0, 2);
191225
assertEquals(-1, found);
192-
testEos(inputStream);
226+
testEos((T) inputStream);
193227
}
194228
}
195229

@@ -202,7 +236,7 @@ public void testReadArrayFully() throws IOException {
202236
assertArrayEquals(new byte[] { 'a', 'b', 'c', 0, 0 }, dest);
203237
found = inputStream.read(dest);
204238
assertEquals(-1, found);
205-
testEos(inputStream);
239+
testEos((T) inputStream);
206240
}
207241
}
208242

@@ -219,7 +253,7 @@ public void testReadArrayPartial() throws IOException {
219253
assertArrayEquals(new byte[] { 'c', 0 }, dest);
220254
found = inputStream.read(dest);
221255
assertEquals(-1, found);
222-
testEos(inputStream);
256+
testEos((T) inputStream);
223257
}
224258
}
225259

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@
3030
public class ThrottledInputStreamTest extends ProxyInputStreamTest<ThrottledInputStream> {
3131

3232
@Override
33-
@SuppressWarnings("resource")
33+
@SuppressWarnings({ "resource" })
3434
protected ThrottledInputStream createFixture() throws IOException {
35-
return ThrottledInputStream.builder().setInputStream(createProxySource()).get();
35+
return ThrottledInputStream.builder().setInputStream(createOriginInputStream()).get();
3636
}
3737

3838
@Test

0 commit comments

Comments
 (0)