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 }