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