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.IOException;
022import java.io.Reader;
023import java.io.UncheckedIOException;
024import java.nio.CharBuffer;
025import java.nio.charset.Charset;
026
027import org.apache.commons.io.build.AbstractOrigin;
028import org.apache.commons.io.build.AbstractStreamBuilder;
029import org.apache.commons.io.function.Uncheck;
030
031/**
032 * A {@link BufferedReader} that throws {@link UncheckedIOException} instead of {@link IOException}.
033 * <p>
034 * To build an instance, see {@link Builder}.
035 * </p>
036 *
037 * @see BufferedReader
038 * @see IOException
039 * @see UncheckedIOException
040 * @since 2.12.0
041 */
042public final class UncheckedBufferedReader extends BufferedReader {
043
044    /**
045     * Builds a new {@link UncheckedBufferedReader} instance.
046     * <p>
047     * Using File IO:
048     * </p>
049     * <pre>{@code
050     * UncheckedBufferedReader s = UncheckedBufferedReader.builder()
051     *   .setFile(file)
052     *   .setBufferSize(8192)
053     *   .setCharset(Charset.defaultCharset())
054     *   .get();}
055     * </pre>
056     * <p>
057     * Using NIO Path:
058     * </p>
059     * <pre>{@code
060     * UncheckedBufferedReader s = UncheckedBufferedReader.builder()
061     *   .setPath(path)
062     *   .setBufferSize(8192)
063     *   .setCharset(Charset.defaultCharset())
064     *   .get();}
065     * </pre>
066     */
067    public static class Builder extends AbstractStreamBuilder<UncheckedBufferedReader, Builder> {
068
069        /**
070         * Constructs a new instance.
071         * <p>
072         * This builder use the aspects Reader, Charset, buffer size.
073         * </p>
074         * <p>
075         * You must provide an origin that can be converted to a Reader by this builder, otherwise, this call will throw an
076         * {@link UnsupportedOperationException}.
077         * </p>
078         *
079         * @return a new instance.
080         * @throws UnsupportedOperationException if the origin cannot provide a Reader.
081         * @throws IllegalStateException if the {@code origin} is {@code null}.
082         * @see AbstractOrigin#getReader(Charset)
083         */
084        @Override
085        public UncheckedBufferedReader get() {
086            // This an unchecked class, so this method is as well.
087            return Uncheck.get(() -> new UncheckedBufferedReader(checkOrigin().getReader(getCharset()), getBufferSize()));
088        }
089
090    }
091
092    /**
093     * Constructs a new {@link Builder}.
094     *
095     * @return a new {@link Builder}.
096     */
097    public static Builder builder() {
098        return new Builder();
099    }
100
101    /**
102     * Constructs a buffering character-input stream that uses an input buffer of the specified size.
103     *
104     * @param reader     A Reader
105     * @param bufferSize Input-buffer size
106     *
107     * @throws IllegalArgumentException If {@code bufferSize <= 0}
108     */
109    private UncheckedBufferedReader(final Reader reader, final int bufferSize) {
110        super(reader, bufferSize);
111    }
112
113    /**
114     * Calls this method's super and rethrow {@link IOException} as {@link UncheckedIOException}.
115     */
116    @Override
117    public void close() throws UncheckedIOException {
118        Uncheck.run(super::close);
119    }
120
121    /**
122     * Calls this method's super and rethrow {@link IOException} as {@link UncheckedIOException}.
123     */
124    @Override
125    public void mark(final int readAheadLimit) throws UncheckedIOException {
126        Uncheck.accept(super::mark, readAheadLimit);
127    }
128
129    /**
130     * Calls this method's super and rethrow {@link IOException} as {@link UncheckedIOException}.
131     */
132    @Override
133    public int read() throws UncheckedIOException {
134        return Uncheck.get(super::read);
135    }
136
137    /**
138     * Calls this method's super and rethrow {@link IOException} as {@link UncheckedIOException}.
139     */
140    @Override
141    public int read(final char[] cbuf) throws UncheckedIOException {
142        return Uncheck.apply(super::read, cbuf);
143    }
144
145    /**
146     * Calls this method's super and rethrow {@link IOException} as {@link UncheckedIOException}.
147     */
148    @Override
149    public int read(final char[] cbuf, final int off, final int len) throws UncheckedIOException {
150        return Uncheck.apply(super::read, cbuf, off, len);
151    }
152
153    /**
154     * Calls this method's super and rethrow {@link IOException} as {@link UncheckedIOException}.
155     */
156    @Override
157    public int read(final CharBuffer target) throws UncheckedIOException {
158        return Uncheck.apply(super::read, target);
159    }
160
161    /**
162     * Calls this method's super and rethrow {@link IOException} as {@link UncheckedIOException}.
163     */
164    @Override
165    public String readLine() throws UncheckedIOException {
166        return Uncheck.get(super::readLine);
167    }
168
169    /**
170     * Calls this method's super and rethrow {@link IOException} as {@link UncheckedIOException}.
171     */
172    @Override
173    public boolean ready() throws UncheckedIOException {
174        return Uncheck.get(super::ready);
175    }
176
177    /**
178     * Calls this method's super and rethrow {@link IOException} as {@link UncheckedIOException}.
179     */
180    @Override
181    public void reset() throws UncheckedIOException {
182        Uncheck.run(super::reset);
183    }
184
185    /**
186     * Calls this method's super and rethrow {@link IOException} as {@link UncheckedIOException}.
187     */
188    @Override
189    public long skip(final long n) throws UncheckedIOException {
190        return Uncheck.apply(super::skip, n);
191    }
192
193}