View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.io.output;
19  
20  import java.io.IOException;
21  import java.io.Writer;
22  import java.util.Objects;
23  
24  import org.apache.commons.io.IOUtils;
25  
26  /**
27   * Writer implementation that writes the data to an {@link Appendable} Object.
28   * <p>
29   * For example, can be used with a {@link StringBuilder} or {@link StringBuffer}.
30   * </p>
31   *
32   * @since 2.7
33   * @see Appendable
34   * @param <T> The type of the {@link Appendable} wrapped by this AppendableWriter.
35   */
36  public class AppendableWriter<T extends Appendable> extends Writer {
37  
38      private final T appendable;
39  
40      /**
41       * Constructs a new instance with the specified appendable.
42       *
43       * @param appendable the appendable to write to.
44       */
45      public AppendableWriter(final T appendable) {
46          this.appendable = appendable;
47      }
48  
49      /**
50       * Appends the specified character to the underlying appendable.
51       *
52       * @param c the character to append.
53       * @return this writer.
54       * @throws IOException If an I/O error occurs.
55       */
56      @Override
57      public Writer append(final char c) throws IOException {
58          appendable.append(c);
59          return this;
60      }
61  
62      /**
63       * Appends the specified character sequence to the underlying appendable.
64       *
65       * @param csq the character sequence to append.
66       * @return this writer.
67       * @throws IOException If an I/O error occurs.
68       */
69      @Override
70      public Writer append(final CharSequence csq) throws IOException {
71          appendable.append(csq);
72          return this;
73      }
74  
75      /**
76       * Appends a subsequence of the specified character sequence to the underlying appendable.
77       *
78       * @param csq   the character sequence from which a subsequence will be appended
79       * @param start the index of the first character in the subsequence
80       * @param end   the index of the character following the last character in the subsequence
81       * @return this writer
82       * @throws IndexOutOfBoundsException If {@code start} or {@code end} are negative, {@code start} is greater than
83       *                                   {@code end}, or {@code end} is greater than {@code csq.length()}.
84       * @throws IOException If an I/O error occurs.
85       */
86      @Override
87      public Writer append(final CharSequence csq, final int start, final int end) throws IOException {
88          appendable.append(csq, start, end);
89          return this;
90      }
91  
92      /**
93       * Closes the stream. This implementation does nothing.
94       *
95       * @throws IOException Thrown by a subclass.
96       */
97      @Override
98      public void close() throws IOException {
99          // noop
100     }
101 
102     /**
103      * Flushes the stream. This implementation does nothing.
104      *
105      * @throws IOException Thrown by a subclass.
106      */
107     @Override
108     public void flush() throws IOException {
109         // noop
110     }
111 
112     /**
113      * Gets the target appendable.
114      *
115      * @return the target appendable.
116      */
117     public T getAppendable() {
118         return appendable;
119     }
120 
121     /**
122      * Writes a portion of an array of characters to the underlying appendable.
123      *
124      * @param cbuf an array with the characters to write.
125      * @param off  offset from which to start writing characters.
126      * @param len  number of characters to write.
127      * @throws NullPointerException if the array is {@code null}.
128      * @throws IndexOutOfBoundsException if {@code off} or {@code len} are negative, or if {@code off + len} is greater than {@code cbuf.length}.
129      * @throws IOException If an I/O error occurs.
130      */
131     @Override
132     public void write(final char[] cbuf, final int off, final int len) throws IOException {
133         IOUtils.checkFromIndexSize(cbuf, off, len);
134         for (int i = 0; i < len; i++) {
135             appendable.append(cbuf[off + i]);
136         }
137     }
138 
139     /**
140      * Writes a character to the underlying appendable.
141      *
142      * @param c the character to write.
143      * @throws IOException If an I/O error occurs.
144      */
145     @Override
146     public void write(final int c) throws IOException {
147         appendable.append((char) c);
148     }
149 
150     /**
151      * Writes a portion of a String to the underlying appendable.
152      *
153      * @param str a string.
154      * @param off offset from which to start writing characters.
155      * @param len number of characters to write.
156      * @throws NullPointerException if the string is {@code null}.
157      * @throws IndexOutOfBoundsException if {@code off} or {@code len} are negative, or if {@code off + len} is greater than {@code str.length()}.
158      * @throws IOException If an I/O error occurs.
159      */
160     @Override
161     public void write(final String str, final int off, final int len) throws IOException {
162         // appendable.append will add "null" for a null String; add an explicit null check
163         Objects.requireNonNull(str, "str");
164         appendable.append(str, off, off + len);
165     }
166 }