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 a01bbfbe Add BrokenInputStream.Builder
a01bbfbe is described below
commit a01bbfbe49203c91003a611efcb6eff673400b0c
Author: Gary Gregory <[email protected]>
AuthorDate: Fri Dec 22 19:58:15 2023 -0500
Add BrokenInputStream.Builder
---
src/changes/changes.xml | 1 +
.../commons/io/input/BoundedInputStream.java | 148 +++++++++++++++++----
.../commons/io/input/BoundedInputStreamTest.java | 45 ++++---
3 files changed, 147 insertions(+), 47 deletions(-)
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index be111b51..a28b73e0 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -89,6 +89,7 @@ The <action> type attribute can be add,update,fix,remove.
<action dev="ggregory" type="add" due-to="Gary
Gregory">Add FileTimes.isUnixTime(FileTime).</action>
<action dev="ggregory" type="add" due-to="Gary
Gregory">Add FileTimes.isUnixTime(long).</action>
<action dev="ggregory" type="add" due-to="Gary
Gregory">Add FileTimes.toUnixTime(FileTime).</action>
+ <action dev="ggregory" type="add" due-to="Gary
Gregory">Add BrokenInputStream.Builder.</action>
<!-- UPDATE -->
<action dev="ggregory" type="fix" due-to="Gary
Gregory">Bump commons.bytebuddy.version from 1.14.10 to 1.14.11 #534.</action>
</release>
diff --git a/src/main/java/org/apache/commons/io/input/BoundedInputStream.java
b/src/main/java/org/apache/commons/io/input/BoundedInputStream.java
index e1fcf905..6ddcf42d 100644
--- a/src/main/java/org/apache/commons/io/input/BoundedInputStream.java
+++ b/src/main/java/org/apache/commons/io/input/BoundedInputStream.java
@@ -22,6 +22,9 @@ import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.io.build.AbstractStreamBuilder;
+
/**
* Reads bytes up to a maximum length, if its count goes above that, it stops.
* <p>
@@ -34,6 +37,80 @@ import java.io.InputStream;
*/
public class BoundedInputStream extends FilterInputStream {
+ /**
+ * Builds a new {@link BoundedInputStream} instance.
+ *
+ * <h2>Using NIO</h2>
+ *
+ * <pre>{@code
+ * BoundedInputStream s =
BoundedInputStream.builder().setPath(Paths.get("MyFile.xml")).setMaxLength(1024).setPropagateClose(false).get();
+ * }
+ * </pre>
+ *
+ * <h2>Using IO</h2>
+ *
+ * <pre>{@code
+ * BoundedInputStream s = BoundedInputStream.builder().setFile(new
File("MyFile.xml")).setMaxLength(1024).setPropagateClose(false).get();
+ * }
+ * </pre>
+ *
+ * @since 2.16.0
+ */
+ public static class Builder extends
AbstractStreamBuilder<BoundedInputStream, Builder> {
+
+ /** The max count of bytes to read. */
+ private long maxLength = EOF;
+
+ /** Flag if close should be propagated. */
+ private boolean propagateClose = true;
+
+ @SuppressWarnings("resource")
+ @Override
+ public BoundedInputStream get() throws IOException {
+ return new BoundedInputStream(getInputStream(), maxLength,
propagateClose);
+ }
+
+ /**
+ * Sets the maximum number of bytes to return.
+ * <p>
+ * Default is {@value IOUtils#EOF}.
+ * </p>
+ *
+ * @param maxLength The maximum number of bytes to return.
+ * @return this.
+ */
+ public Builder setMaxLength(final long maxLength) {
+ this.maxLength = maxLength;
+ return this;
+ }
+
+ /**
+ * Sets whether the {@link #close()} method should propagate to the
underling {@link InputStream}.
+ * <p>
+ * Default is true.
+ * </p>
+ *
+ * @param propagateClose {@code true} if calling {@link #close()}
propagates to the {@code close()} method of the underlying stream or {@code
false} if
+ * it does not.
+ * @return this.
+ */
+ public Builder setPropagateClose(final boolean propagateClose) {
+ this.propagateClose = propagateClose;
+ return this;
+ }
+
+ }
+
+ /**
+ * Constructs a new {@link Builder}.
+ *
+ * @return a new {@link Builder}.
+ * @since 2.16.0
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
/** The max count of bytes to read. */
private final long maxCount;
@@ -43,26 +120,32 @@ public class BoundedInputStream extends FilterInputStream {
/** The marked position. */
private long mark = EOF;
- /** Flag if close should be propagated. */
+ /**
+ * Flag if close should be propagated.
+ *
+ * TODO Make final in 3.0.
+ */
private boolean propagateClose = true;
/**
- * Constructs a new {@link BoundedInputStream} that wraps the given input
- * stream and is unlimited.
+ * Constructs a new {@link BoundedInputStream} that wraps the given input
stream and is unlimited.
*
* @param in The wrapped input stream.
+ * @deprecated Use {@link Builder#get()}.
*/
+ @Deprecated
public BoundedInputStream(final InputStream in) {
this(in, EOF);
}
/**
- * Constructs a new {@link BoundedInputStream} that wraps the given input
- * stream and limits it to a certain size.
+ * Constructs a new {@link BoundedInputStream} that wraps the given input
stream and limits it to a certain size.
*
* @param inputStream The wrapped input stream.
- * @param maxLength The maximum number of bytes to return.
+ * @param maxLength The maximum number of bytes to return.
+ * @deprecated Use {@link Builder#get()}.
*/
+ @Deprecated
public BoundedInputStream(final InputStream inputStream, final long
maxLength) {
// Some badly designed methods - e.g. the servlet API - overload length
// such that "-1" means stream finished
@@ -70,6 +153,22 @@ public class BoundedInputStream extends FilterInputStream {
this.maxCount = maxLength;
}
+ /**
+ * Constructs a new {@link BoundedInputStream} that wraps the given input
stream and limits it to a certain size.
+ *
+ * @param inputStream The wrapped input stream.
+ * @param maxLength The maximum number of bytes to return.
+ * @param propagateClose {@code true} if calling {@link #close()}
propagates to the {@code close()} method of the underlying stream or {@code
false} if it
+ * does not.
+ */
+ private BoundedInputStream(final InputStream inputStream, final long
maxLength, final boolean propagateClose) {
+ // Some badly designed methods - e.g. the servlet API - overload length
+ // such that "-1" means stream finished
+ super(inputStream);
+ this.maxCount = maxLength;
+ this.propagateClose = propagateClose;
+ }
+
/**
* {@inheritDoc}
*/
@@ -83,8 +182,7 @@ public class BoundedInputStream extends FilterInputStream {
}
/**
- * Invokes the delegate's {@code close()} method
- * if {@link #isPropagateClose()} is {@code true}.
+ * Invokes the delegate's {@code close()} method if {@link
#isPropagateClose()} is {@code true}.
*
* @throws IOException if an I/O error occurs.
*/
@@ -130,12 +228,9 @@ public class BoundedInputStream extends FilterInputStream {
}
/**
- * Tests whether the {@link #close()} method
- * should propagate to the underling {@link InputStream}.
+ * Tests whether the {@link #close()} method should propagate to the
underling {@link InputStream}.
*
- * @return {@code true} if calling {@link #close()}
- * propagates to the {@code close()} method of the
- * underlying stream or {@code false} if it does not.
+ * @return {@code true} if calling {@link #close()} propagates to the
{@code close()} method of the underlying stream or {@code false} if it does not.
*/
public boolean isPropagateClose() {
return propagateClose;
@@ -166,7 +261,7 @@ public class BoundedInputStream extends FilterInputStream {
* A caller has caused a request that would cross the {@code maxLength}
boundary.
*
* @param maxLength The max count of bytes to read.
- * @param count The count of bytes read.
+ * @param count The count of bytes read.
* @throws IOException Subclasses may throw.
* @since 2.12.0
*/
@@ -176,11 +271,9 @@ public class BoundedInputStream extends FilterInputStream {
}
/**
- * Invokes the delegate's {@code read()} method if
- * the current position is less than the limit.
+ * Invokes the delegate's {@code read()} method if the current position is
less than the limit.
*
- * @return the byte read or -1 if the end of stream or
- * the limit has been reached.
+ * @return the byte read or -1 if the end of stream or the limit has been
reached.
* @throws IOException if an I/O error occurs.
*/
@Override
@@ -200,8 +293,7 @@ public class BoundedInputStream extends FilterInputStream {
* Invokes the delegate's {@code read(byte[])} method.
*
* @param b the buffer to read the bytes into
- * @return the number of bytes read or -1 if the end of stream or
- * the limit has been reached.
+ * @return the number of bytes read or -1 if the end of stream or the
limit has been reached.
* @throws IOException if an I/O error occurs.
*/
@Override
@@ -212,11 +304,10 @@ public class BoundedInputStream extends FilterInputStream
{
/**
* Invokes the delegate's {@code read(byte[], int, int)} method.
*
- * @param b the buffer to read the bytes into
+ * @param b the buffer to read the bytes into
* @param off The start offset
* @param len The number of bytes to read
- * @return the number of bytes read or -1 if the end of stream or
- * the limit has been reached.
+ * @return the number of bytes read or -1 if the end of stream or the
limit has been reached.
* @throws IOException if an I/O error occurs.
*/
@Override
@@ -248,14 +339,13 @@ public class BoundedInputStream extends FilterInputStream
{
}
/**
- * Sets whether the {@link #close()} method
- * should propagate to the underling {@link InputStream}.
+ * Sets whether the {@link #close()} method should propagate to the
underling {@link InputStream}.
*
- * @param propagateClose {@code true} if calling
- * {@link #close()} propagates to the {@code close()}
- * method of the underlying stream or
- * {@code false} if it does not.
+ * @param propagateClose {@code true} if calling {@link #close()}
propagates to the {@code close()} method of the underlying stream or {@code
false} if it
+ * does not.
+ * @deprecated Use {@link Builder#setPropagateClose(boolean)}.
*/
+ @Deprecated
public void setPropagateClose(final boolean propagateClose) {
this.propagateClose = propagateClose;
}
diff --git
a/src/test/java/org/apache/commons/io/input/BoundedInputStreamTest.java
b/src/test/java/org/apache/commons/io/input/BoundedInputStreamTest.java
index cd8556c3..a8678a47 100644
--- a/src/test/java/org/apache/commons/io/input/BoundedInputStreamTest.java
+++ b/src/test/java/org/apache/commons/io/input/BoundedInputStreamTest.java
@@ -21,6 +21,7 @@ import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.ByteArrayInputStream;
+import java.nio.charset.StandardCharsets;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.commons.io.IOUtils;
@@ -38,11 +39,12 @@ public class BoundedInputStreamTest {
}
}
+ @SuppressWarnings("deprecation")
@Test
public void testOnMaxLength() throws Exception {
BoundedInputStream bounded;
- final byte[] helloWorld = "Hello World".getBytes();
- final byte[] hello = "Hello".getBytes();
+ final byte[] helloWorld = "Hello
World".getBytes(StandardCharsets.UTF_8);
+ final byte[] hello = "Hello".getBytes(StandardCharsets.UTF_8);
final AtomicBoolean boolRef = new AtomicBoolean();
// limit = length
@@ -127,31 +129,38 @@ public class BoundedInputStreamTest {
@Test
public void testReadArray() throws Exception {
- BoundedInputStream bounded;
- final byte[] helloWorld = "Hello World".getBytes();
- final byte[] hello = "Hello".getBytes();
-
- bounded = new BoundedInputStream(new ByteArrayInputStream(helloWorld));
- compare("limit = -1", helloWorld, IOUtils.toByteArray(bounded));
+ final byte[] helloWorld = "Hello
World".getBytes(StandardCharsets.UTF_8);
+ final byte[] hello = "Hello".getBytes(StandardCharsets.UTF_8);
- bounded = new BoundedInputStream(new ByteArrayInputStream(helloWorld),
0);
- compare("limit = 0", IOUtils.EMPTY_BYTE_ARRAY,
IOUtils.toByteArray(bounded));
+ try (BoundedInputStream bounded =
BoundedInputStream.builder().setInputStream(new
ByteArrayInputStream(helloWorld)).get()) {
+ compare("limit = -1", helloWorld, IOUtils.toByteArray(bounded));
+ }
- bounded = new BoundedInputStream(new ByteArrayInputStream(helloWorld),
helloWorld.length);
- compare("limit = length", helloWorld, IOUtils.toByteArray(bounded));
+ try (BoundedInputStream bounded =
BoundedInputStream.builder().setInputStream(new
ByteArrayInputStream(helloWorld)).setMaxLength(0).get()) {
+ compare("limit = 0", IOUtils.EMPTY_BYTE_ARRAY,
IOUtils.toByteArray(bounded));
+ }
- bounded = new BoundedInputStream(new ByteArrayInputStream(helloWorld),
helloWorld.length + 1);
- compare("limit > length", helloWorld, IOUtils.toByteArray(bounded));
+ try (BoundedInputStream bounded =
BoundedInputStream.builder().setInputStream(new
ByteArrayInputStream(helloWorld)).setMaxLength(helloWorld.length)
+ .get()) {
+ compare("limit = length", helloWorld,
IOUtils.toByteArray(bounded));
+ }
- bounded = new BoundedInputStream(new ByteArrayInputStream(helloWorld),
helloWorld.length - 6);
- compare("limit < length", hello, IOUtils.toByteArray(bounded));
+ try (BoundedInputStream bounded =
BoundedInputStream.builder().setInputStream(new
ByteArrayInputStream(helloWorld)).setMaxLength(helloWorld.length + 1)
+ .get()) {
+ compare("limit > length", helloWorld,
IOUtils.toByteArray(bounded));
+ }
+ try (BoundedInputStream bounded =
BoundedInputStream.builder().setInputStream(new
ByteArrayInputStream(helloWorld)).setMaxLength(helloWorld.length - 6)
+ .get()) {
+ compare("limit < length", hello, IOUtils.toByteArray(bounded));
+ }
}
+ @SuppressWarnings("deprecation")
@Test
public void testReadSingle() throws Exception {
BoundedInputStream bounded;
- final byte[] helloWorld = "Hello World".getBytes();
- final byte[] hello = "Hello".getBytes();
+ final byte[] helloWorld = "Hello
World".getBytes(StandardCharsets.UTF_8);
+ final byte[] hello = "Hello".getBytes(StandardCharsets.UTF_8);
// limit = length
bounded = new BoundedInputStream(new ByteArrayInputStream(helloWorld),
helloWorld.length);