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);

Reply via email to