001/*
002 *  Licensed to the Apache Software Foundation (ASF) under one or more
003 *  contributor license agreements.  See the NOTICE file distributed with
004 *  this work for additional information regarding copyright ownership.
005 *  The ASF licenses this file to You under the Apache License, Version 2.0
006 *  (the "License"); you may not use this file except in compliance with
007 *  the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 *  Unless required by applicable law or agreed to in writing, software
012 *  distributed under the License is distributed on an "AS IS" BASIS,
013 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 *  See the License for the specific language governing permissions and
015 *  limitations under the License.
016 */
017
018package org.apache.commons.io.input;
019
020import java.io.BufferedReader;
021import java.io.FilterInputStream;
022import java.io.IOException;
023import java.io.InputStream;
024import java.io.UncheckedIOException;
025
026import org.apache.commons.io.build.AbstractStreamBuilder;
027import org.apache.commons.io.function.Uncheck;
028
029/**
030 * A {@link BufferedReader} that throws {@link UncheckedIOException} instead of {@link IOException}.
031 * <p>
032 * To build an instance, use {@link Builder}.
033 * </p>
034 *
035 * @see Builder
036 * @see BufferedReader
037 * @see IOException
038 * @see UncheckedIOException
039 * @since 2.12.0
040 */
041public final class UncheckedFilterInputStream extends FilterInputStream {
042
043    // @formatter:off
044    /**
045     * Builds a new {@link UncheckedFilterInputStream}.
046     *
047     * <p>
048     * Using File IO:
049     * </p>
050     * <pre>{@code
051     * UncheckedFilterInputStream s = UncheckedFilterInputStream.builder()
052     *   .setFile(file)
053     *   .get();}
054     * </pre>
055     * <p>
056     * Using NIO Path:
057     * </p>
058     * <pre>{@code
059     * UncheckedFilterInputStream s = UncheckedFilterInputStream.builder()
060     *   .setPath(path)
061     *   .get();}
062     * </pre>
063     *
064     * @see #get()
065     */
066    // @formatter:on
067    public static class Builder extends AbstractStreamBuilder<UncheckedFilterInputStream, Builder> {
068
069        /**
070         * Constructs a new builder of {@link UncheckedFilterInputStream}.
071         */
072        public Builder() {
073            // empty
074        }
075
076        /**
077         * Builds a new {@link UncheckedFilterInputStream}.
078         * <p>
079         * You must set an aspect that supports {@link #getInputStream()} on this builder, otherwise, this method throws an exception.
080         * </p>
081         * <p>
082         * This builder uses the following aspects:
083         * </p>
084         * <ul>
085         * <li>{@link #getInputStream()} gets the target aspect.</li>
086         * </ul>
087         *
088         * @return a new instance.
089         * @throws UnsupportedOperationException if the origin cannot provide an {@link #getInputStream()}.
090         * @see #getInputStream()
091         * @see #getUnchecked()
092         */
093        @SuppressWarnings("resource")
094        @Override
095        public UncheckedFilterInputStream get() {
096            // This an unchecked class, so this method is as well.
097            return Uncheck.get(() -> new UncheckedFilterInputStream(getInputStream()));
098        }
099
100    }
101
102    /**
103     * Constructs a new {@link Builder}.
104     *
105     * @return a new {@link Builder}.
106     */
107    public static Builder builder() {
108        return new Builder();
109    }
110
111    /**
112     * Constructs a {@link UncheckedFilterInputStream}.
113     *
114     * @param inputStream the underlying input stream, or {@code null} if this instance is to be created without an
115     *        underlying stream.
116     */
117    private UncheckedFilterInputStream(final InputStream inputStream) {
118        super(inputStream);
119    }
120
121    /**
122     * Calls this method's super and rethrow {@link IOException} as {@link UncheckedIOException}.
123     */
124    @Override
125    public int available() throws UncheckedIOException {
126        return Uncheck.getAsInt(super::available);
127    }
128
129    /**
130     * Calls this method's super and rethrow {@link IOException} as {@link UncheckedIOException}.
131     */
132    @Override
133    public void close() throws UncheckedIOException {
134        Uncheck.run(super::close);
135    }
136
137    /**
138     * Calls this method's super and rethrow {@link IOException} as {@link UncheckedIOException}.
139     */
140    @Override
141    public int read() throws UncheckedIOException {
142        return Uncheck.getAsInt(super::read);
143    }
144
145    /**
146     * Calls this method's super and rethrow {@link IOException} as {@link UncheckedIOException}.
147     */
148    @Override
149    public int read(final byte[] b) throws UncheckedIOException {
150        return Uncheck.apply(super::read, b);
151    }
152
153    /**
154     * Calls this method's super and rethrow {@link IOException} as {@link UncheckedIOException}.
155     */
156    @Override
157    public int read(final byte[] b, final int off, final int len) throws UncheckedIOException {
158        return Uncheck.apply(super::read, b, off, len);
159    }
160
161    /**
162     * Calls this method's super and rethrow {@link IOException} as {@link UncheckedIOException}.
163     */
164    @Override
165    public synchronized void reset() throws UncheckedIOException {
166        Uncheck.run(super::reset);
167    }
168
169    /**
170     * Calls this method's super and rethrow {@link IOException} as {@link UncheckedIOException}.
171     */
172    @Override
173    public long skip(final long n) throws UncheckedIOException {
174        return Uncheck.apply(super::skip, n);
175    }
176
177}