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
commit 256436e90a62eb7394b2962c0fba7b4f6e8ab3bf Author: Gary Gregory <garydgreg...@gmail.com> AuthorDate: Sat May 20 10:44:57 2023 -0400 Refactor and pull up CharSequenceInputStream.Builder.setCharSequence() --- .../apache/commons/io/build/AbstractOrigin.java | 44 +++++++++++++++++- .../commons/io/build/AbstractOriginSupplier.java | 45 +++++++++++++----- .../commons/io/build/AbstractStreamBuilder.java | 13 ++++++ .../commons/io/input/AutoCloseInputStream.java | 54 ++++++++++++++++++++++ .../commons/io/input/CharSequenceInputStream.java | 20 ++------ .../commons/io/input/AutoCloseInputStreamTest.java | 33 +++++++++++-- 6 files changed, 177 insertions(+), 32 deletions(-) diff --git a/src/main/java/org/apache/commons/io/build/AbstractOrigin.java b/src/main/java/org/apache/commons/io/build/AbstractOrigin.java index 6624bfb6..da4652ef 100644 --- a/src/main/java/org/apache/commons/io/build/AbstractOrigin.java +++ b/src/main/java/org/apache/commons/io/build/AbstractOrigin.java @@ -68,7 +68,37 @@ public abstract class AbstractOrigin<T, B extends AbstractOrigin<T, B>> extends @Override public InputStream getInputStream(final OpenOption... options) throws IOException { - return new ByteArrayInputStream(getByteArray()); + return new ByteArrayInputStream(origin); + } + + } + + /** + * A {@link CharSequence} origin. + */ + public static class CharSequenceOrigin extends AbstractOrigin<CharSequence, CharSequenceOrigin> { + + /** + * Constructs a new instance for the given origin. + * + * @param origin The origin. + */ + public CharSequenceOrigin(final CharSequence origin) { + super(origin); + } + + @Override + public CharSequence getCharSequence(final Charset charset) { + // No conversion + return get(); + } + + @Override + public InputStream getInputStream(final OpenOption... options) throws IOException { + // TODO Pass in a Charset? Consider if call sites actually need this. + return new ByteArrayInputStream(origin.toString().getBytes(Charset.defaultCharset())); + // Needs [IO-795] CharSequenceInputStream.reset() only works once. + // return CharSequenceInputStream.builder().setCharSequence(getCharSequence(Charset.defaultCharset())).get(); } } @@ -292,6 +322,18 @@ public abstract class AbstractOrigin<T, B extends AbstractOrigin<T, B>> extends return Files.readAllBytes(getPath()); } + /** + * Gets this origin as a byte array, if possible. + * + * @param charset The charset to use if conversion from bytes is needed. + * @return this origin as a byte array, if possible. + * @throws IOException if an I/O error occurs. + * @throws UnsupportedOperationException if the origin cannot be converted to a Path. + */ + public CharSequence getCharSequence(final Charset charset) throws IOException { + return new String(getByteArray(), charset); + } + /** * Gets this origin as a Path, if possible. * diff --git a/src/main/java/org/apache/commons/io/build/AbstractOriginSupplier.java b/src/main/java/org/apache/commons/io/build/AbstractOriginSupplier.java index 706ec285..ef691f44 100644 --- a/src/main/java/org/apache/commons/io/build/AbstractOriginSupplier.java +++ b/src/main/java/org/apache/commons/io/build/AbstractOriginSupplier.java @@ -28,6 +28,7 @@ import java.nio.file.Paths; import java.util.Objects; import org.apache.commons.io.build.AbstractOrigin.ByteArrayOrigin; +import org.apache.commons.io.build.AbstractOrigin.CharSequenceOrigin; import org.apache.commons.io.build.AbstractOrigin.FileOrigin; import org.apache.commons.io.build.AbstractOrigin.InputStreamOrigin; import org.apache.commons.io.build.AbstractOrigin.OutputStreamOrigin; @@ -48,18 +49,29 @@ public abstract class AbstractOriginSupplier<T, B extends AbstractOriginSupplier /** * Creates a new byte array origin for a byte array. * - * @param origin the file. - * @return a new file origin + * @param origin the byte array. + * @return a new byte array origin. */ protected static ByteArrayOrigin newByteArrayOrigin(final byte[] origin) { return new ByteArrayOrigin(origin); } + /** + * Creates a new CharSequence origin for a CharSequence. + * + * @param origin the CharSequence. + * @return a new file origin. + * @since 2.13.0 + */ + protected static CharSequenceOrigin newCharSequenceOrigin(final CharSequence origin) { + return new CharSequenceOrigin(origin); + } + /** * Creates a new file origin for a file. * * @param origin the file. - * @return a new file origin + * @return a new file origin. */ protected static FileOrigin newFileOrigin(final File origin) { return new FileOrigin(origin); @@ -69,7 +81,7 @@ public abstract class AbstractOriginSupplier<T, B extends AbstractOriginSupplier * Creates a new file origin for a file path. * * @param origin the file path. - * @return a new file origin + * @return a new file origin. */ protected static FileOrigin newFileOrigin(final String origin) { return new FileOrigin(new File(origin)); @@ -79,7 +91,7 @@ public abstract class AbstractOriginSupplier<T, B extends AbstractOriginSupplier * Creates a new input stream origin for a file. * * @param origin the input stream. - * @return a new input stream origin + * @return a new input stream origin. */ protected static InputStreamOrigin newInputStreamOrigin(final InputStream origin) { return new InputStreamOrigin(origin); @@ -89,7 +101,7 @@ public abstract class AbstractOriginSupplier<T, B extends AbstractOriginSupplier * Creates a new output stream origin for a file. * * @param origin the output stream. - * @return a new output stream origin + * @return a new output stream origin. */ protected static OutputStreamOrigin newOutputStreamOrigin(final OutputStream origin) { return new OutputStreamOrigin(origin); @@ -99,7 +111,7 @@ public abstract class AbstractOriginSupplier<T, B extends AbstractOriginSupplier * Creates a new path origin for a file. * * @param origin the path. - * @return a new path origin + * @return a new path origin. */ protected static PathOrigin newPathOrigin(final Path origin) { return new PathOrigin(origin); @@ -109,7 +121,7 @@ public abstract class AbstractOriginSupplier<T, B extends AbstractOriginSupplier * Creates a new path name origin for a path name. * * @param origin the path name. - * @return a new path name origin + * @return a new path name origin. */ protected static PathOrigin newPathOrigin(final String origin) { return new PathOrigin(Paths.get(origin)); @@ -119,7 +131,7 @@ public abstract class AbstractOriginSupplier<T, B extends AbstractOriginSupplier * Creates a new reader origin for a reader. * * @param origin the reader. - * @return a new reader origin + * @return a new reader origin. */ protected static ReaderOrigin newReaderOrigin(final Reader origin) { return new ReaderOrigin(origin); @@ -129,7 +141,7 @@ public abstract class AbstractOriginSupplier<T, B extends AbstractOriginSupplier * Creates a new reader origin for a URI. * * @param origin the URI. - * @return a new URI origin + * @return a new URI origin. */ protected static URIOrigin newURIOrigin(final URI origin) { return new URIOrigin(origin); @@ -139,7 +151,7 @@ public abstract class AbstractOriginSupplier<T, B extends AbstractOriginSupplier * Creates a new writer origin for a file. * * @param origin the writer. - * @return a new writer origin + * @return a new writer . */ protected static WriterOrigin newWriterOrigin(final Writer origin) { return new WriterOrigin(origin); @@ -188,6 +200,17 @@ public abstract class AbstractOriginSupplier<T, B extends AbstractOriginSupplier return setOrigin(newByteArrayOrigin(origin)); } + /** + * Sets a new origin. + * + * @param origin the new origin. + * @return this + * @since 2.13.0 + */ + public B setCharSequence(final CharSequence origin) { + return setOrigin(newCharSequenceOrigin(origin)); + } + /** * Sets a new origin. * diff --git a/src/main/java/org/apache/commons/io/build/AbstractStreamBuilder.java b/src/main/java/org/apache/commons/io/build/AbstractStreamBuilder.java index 3c34689f..3cbe1698 100644 --- a/src/main/java/org/apache/commons/io/build/AbstractStreamBuilder.java +++ b/src/main/java/org/apache/commons/io/build/AbstractStreamBuilder.java @@ -79,6 +79,19 @@ public abstract class AbstractStreamBuilder<T, B extends AbstractStreamBuilder<T return bufferSizeDefault; } + /** + * Gets a CharSequence from the origin with a Charset. + * + * @return An input stream + * @throws IOException if an I/O error occurs. + * @throws UnsupportedOperationException if the origin cannot be converted to a CharSequence. + * @see AbstractOrigin#getCharSequence(Charset) + * @since 2.13.0 + */ + protected CharSequence getCharSequence() throws IOException { + return getOrigin().getCharSequence(getCharset()); + } + /** * Gets the Charset, defaults to {@link Charset#defaultCharset()}. * diff --git a/src/main/java/org/apache/commons/io/input/AutoCloseInputStream.java b/src/main/java/org/apache/commons/io/input/AutoCloseInputStream.java index bf3d317b..05885896 100644 --- a/src/main/java/org/apache/commons/io/input/AutoCloseInputStream.java +++ b/src/main/java/org/apache/commons/io/input/AutoCloseInputStream.java @@ -21,6 +21,8 @@ import static org.apache.commons.io.IOUtils.EOF; import java.io.IOException; import java.io.InputStream; +import org.apache.commons.io.build.AbstractStreamBuilder; + /** * Proxy stream that closes and discards the underlying stream as soon as the * end of input has been reached or when the stream is explicitly closed. @@ -38,11 +40,63 @@ import java.io.InputStream; */ public class AutoCloseInputStream extends ProxyInputStream { + /** + * Builds a new {@link AutoCloseInputStream} instance. + * <p> + * For example: + * </p> + * + * <pre>{@code + * AutoCloseInputStream s = AutoCloseInputStream.builder() + * .setPath(path) + * .get();} + * </pre> + * + * <pre>{@code + * AutoCloseInputStream s = AutoCloseInputStream.builder() + * .setInputStream(inputStream) + * .get();} + * </pre> + * + * @since 2.13.0 + */ + public static class Builder extends AbstractStreamBuilder<AutoCloseInputStream, Builder> { + + /** + * Constructs a new instance. + * <p> + * This builder use the aspect InputStream. + * </p> + * + * @return a new instance. + * @throws IOException if an I/O error occurs. + * @throws IllegalArgumentException if the buffer is not large enough to hold a complete character. + */ + @SuppressWarnings("resource") // Caller closes + @Override + public AutoCloseInputStream get() throws IOException { + return new AutoCloseInputStream(getInputStream()); + } + + } + + /** + * Constructs a new {@link Builder}. + * + * @return a new {@link Builder}. + * @since 2.12.0 + */ + public static Builder builder() { + return new Builder(); + } + /** * Creates an automatically closing proxy for the given input stream. * * @param in underlying input stream + * @deprecated Use {@link #builder()} and {@link Builder#get()} */ + @Deprecated public AutoCloseInputStream(final InputStream in) { super(in); } diff --git a/src/main/java/org/apache/commons/io/input/CharSequenceInputStream.java b/src/main/java/org/apache/commons/io/input/CharSequenceInputStream.java index 0c340348..1ccde6ad 100644 --- a/src/main/java/org/apache/commons/io/input/CharSequenceInputStream.java +++ b/src/main/java/org/apache/commons/io/input/CharSequenceInputStream.java @@ -33,6 +33,7 @@ import java.util.Objects; import org.apache.commons.io.Charsets; import org.apache.commons.io.IOUtils; import org.apache.commons.io.build.AbstractStreamBuilder; +import org.apache.commons.io.function.Uncheck; /** * Implements an {@link InputStream} to read from String, StringBuffer, StringBuilder or CharBuffer. @@ -62,12 +63,10 @@ public class CharSequenceInputStream extends InputStream { */ public static class Builder extends AbstractStreamBuilder<CharSequenceInputStream, Builder> { - private CharSequence source; - /** * Constructs a new instance. * <p> - * This builder use the aspects the buffer size, CharSequence, and Charset. + * This builder use the aspects the CharSequence, buffer size, and Charset. * </p> * * @return a new instance. @@ -75,18 +74,7 @@ public class CharSequenceInputStream extends InputStream { */ @Override public CharSequenceInputStream get() { - return new CharSequenceInputStream(source, getCharset(), getBufferSize()); - } - - /** - * Sets the non-null CharSequence. - * - * @param source The source string, MUST not be null. - * @return this. - */ - public Builder setCharSequence(final CharSequence source) { - this.source = Objects.requireNonNull(source, "source"); - return this; + return Uncheck.get(() -> new CharSequenceInputStream(getCharSequence(), getCharset(), getBufferSize())); } } @@ -292,7 +280,7 @@ public class CharSequenceInputStream extends InputStream { // // Since the bBuf is re-used, in general it's necessary to re-encode the data. // - // It should be possible to apply some optimisations however: + // It should be possible to apply some optimizations however: // + use mark/reset on the cBuf and bBuf. This would only work if the buffer had not been (re)filled since // the mark. The code would have to catch InvalidMarkException - does not seem possible to check if mark is // valid otherwise. + Try saving the state of the cBuf before each fillBuffer; it might be possible to diff --git a/src/test/java/org/apache/commons/io/input/AutoCloseInputStreamTest.java b/src/test/java/org/apache/commons/io/input/AutoCloseInputStreamTest.java index 455db058..ca67b2b5 100644 --- a/src/test/java/org/apache/commons/io/input/AutoCloseInputStreamTest.java +++ b/src/test/java/org/apache/commons/io/input/AutoCloseInputStreamTest.java @@ -39,7 +39,7 @@ public class AutoCloseInputStreamTest { @BeforeEach public void setUp() { - data = new byte[] {'x', 'y', 'z'}; + data = new byte[] { 'x', 'y', 'z' }; stream = new AutoCloseInputStream(new ByteArrayInputStream(data) { @Override public void close() { @@ -106,9 +106,34 @@ public class AutoCloseInputStreamTest { } @Test - public void testResetBeforeEnd() throws IOException { - final String inputStr = "1234"; - final AutoCloseInputStream inputStream = new AutoCloseInputStream(new ByteArrayInputStream(inputStr.getBytes())); + public void testResetBeforeEndCtor() throws IOException { + try (final AutoCloseInputStream inputStream = new AutoCloseInputStream(new ByteArrayInputStream("1234".getBytes()))) { + testResetBeforeEnd(inputStream); + } + } + + @Test + public void testResetBeforeEndSetInputStream() throws IOException { + try (final AutoCloseInputStream inputStream = AutoCloseInputStream.builder().setInputStream(new ByteArrayInputStream("1234".getBytes())).get()) { + testResetBeforeEnd(inputStream); + } + } + + @Test + public void testResetBeforeEndSetByteArray() throws IOException { + try (final AutoCloseInputStream inputStream = AutoCloseInputStream.builder().setByteArray("1234".getBytes()).get()) { + testResetBeforeEnd(inputStream); + } + } + + @Test + public void testResetBeforeEndSetCharSequence() throws IOException { + try (final AutoCloseInputStream inputStream = AutoCloseInputStream.builder().setCharSequence("1234").get()) { + testResetBeforeEnd(inputStream); + } + } + + private void testResetBeforeEnd(final AutoCloseInputStream inputStream) throws IOException { inputStream.mark(1); assertEquals('1', inputStream.read()); inputStream.reset();