Skip to content

Commit 3e515ee

Browse files
authored
Improve OutputStream and Writer emulation (#10119)
Add a few convenience methods introduced in Java 11. Fixes #10123
1 parent a6a8496 commit 3e515ee

File tree

6 files changed

+166
-2
lines changed

6 files changed

+166
-2
lines changed

user/super/com/google/gwt/emul/java/io/ByteArrayOutputStream.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919

2020
package java.io;
2121

22+
import java.nio.charset.Charset;
23+
2224
/**
2325
* A specialized {@link OutputStream} for class for writing content to an
2426
* (internal) byte array. As bytes are written to this stream, the byte array
@@ -175,6 +177,18 @@ public String toString(String charsetName) throws UnsupportedEncodingException {
175177
return new String(buf, 0, count, charsetName);
176178
}
177179

180+
/**
181+
* Returns the contents of this ByteArrayOutputStream as a string converted
182+
* according to the encoding declared in {@code charsetName}.
183+
*
184+
* @param charset
185+
* the encoding to use when translating this stream to a string.
186+
* @return this stream's current contents as an encoded string.
187+
*/
188+
public String toString(Charset charset) {
189+
return new String(buf, 0, count, charset);
190+
}
191+
178192
/**
179193
* Writes {@code count} bytes from the byte array {@code buffer} starting at
180194
* offset {@code index} to this stream.
@@ -203,6 +217,18 @@ public void write(byte[] buffer, int offset, int len) {
203217
this.count += len;
204218
}
205219

220+
/**
221+
* Writes all bytes from the byte array {@code buffer} to this stream.
222+
*
223+
* @param buffer
224+
* the buffer to be written.
225+
* @throws NullPointerException
226+
* if {@code buffer} is {@code null}.
227+
*/
228+
public void writeBytes(byte[] buffer) {
229+
write(buffer, 0, buffer.length);
230+
}
231+
206232
/**
207233
* Writes the specified byte {@code oneByte} to the OutputStream. Only the
208234
* low order byte of {@code oneByte} is written.

user/super/com/google/gwt/emul/java/io/OutputStream.java

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
* @see InputStream
4949
*
5050
* <p>The implementation provided by this class behaves as described in the Java
51-
* API documentation except for {@link write(int)} which throws an exception of
51+
* API documentation except for {@link #write(int)} which throws an exception of
5252
* type {@link java.lang.UnsupportedOperationException} instead of being
5353
* abstract.
5454
*/
@@ -130,4 +130,29 @@ public void write(byte[] buffer, int offset, int count) throws IOException {
130130
* if an error occurs while writing to this stream.
131131
*/
132132
public abstract void write(int oneByte) throws IOException;
133+
134+
public static OutputStream nullOutputStream() {
135+
return new OutputStream() {
136+
private boolean closed;
137+
138+
@Override
139+
public void write(int b) throws IOException {
140+
if (closed) {
141+
throw new IOException();
142+
}
143+
}
144+
145+
public void write(byte[] buffer, int offset, int count) throws IOException {
146+
IOUtils.checkOffsetAndCount(buffer, offset, count);
147+
if (closed) {
148+
throw new IOException();
149+
}
150+
}
151+
152+
@Override
153+
public void close() {
154+
closed = true;
155+
}
156+
};
157+
}
133158
}

user/super/com/google/gwt/emul/java/io/Writer.java

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,4 +78,54 @@ public Writer append(CharSequence csq, int start, int end) throws IOException {
7878
write(csq.subSequence(start, end).toString());
7979
return this;
8080
}
81+
82+
public static Writer nullWriter() {
83+
return new Writer() {
84+
private boolean closed;
85+
86+
@Override
87+
public void write(char[] buffer, int off, int len) throws IOException {
88+
IOUtils.checkOffsetAndCount(buffer, off, len);
89+
ensureOpen();
90+
}
91+
92+
public void write(int oneChar) throws IOException {
93+
ensureOpen();
94+
}
95+
96+
public void write(String str, int offset, int count) throws IOException {
97+
IOUtils.checkOffsetAndCount(str, offset, count);
98+
ensureOpen();
99+
}
100+
101+
public Writer append(CharSequence csq) throws IOException {
102+
ensureOpen();
103+
return this;
104+
}
105+
106+
public Writer append(CharSequence csq, int start, int end) throws IOException {
107+
ensureOpen();
108+
if (csq != null) {
109+
IOUtils.checkOffsetAndCount(csq.toString(), start, end - start);
110+
}
111+
return this;
112+
}
113+
114+
@Override
115+
public void flush() throws IOException {
116+
ensureOpen();
117+
}
118+
119+
@Override
120+
public void close() {
121+
closed = true;
122+
}
123+
124+
private void ensureOpen() throws IOException {
125+
if (closed) {
126+
throw new IOException();
127+
}
128+
}
129+
};
130+
}
81131
}

user/test/com/google/gwt/emultest/java/io/ByteArrayOutputStreamTest.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import java.io.ByteArrayOutputStream;
1919
import java.io.IOException;
2020
import java.io.OutputStream;
21+
import java.nio.charset.StandardCharsets;
2122
import java.util.Arrays;
2223

2324
/**
@@ -137,8 +138,17 @@ public void testToStringWithCharsetNameAndNonEmptyStream() throws IOException {
137138
assertEquals(expectedString, actualString);
138139
}
139140

141+
public void testToStringWithCharsetAndNonEmptyStream() throws IOException {
142+
final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(1);
143+
final String expectedString = "Hello";
144+
145+
outputStream.write(expectedString.getBytes(StandardCharsets.UTF_8));
146+
final String actualString = outputStream.toString(StandardCharsets.UTF_8);
147+
assertEquals(expectedString, actualString);
148+
}
149+
140150
public void testWriteSingleValues() throws IOException {
141-
final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(2);
151+
outputStream = new ByteArrayOutputStream(2);
142152
assertEquals(0, outputStream.size());
143153

144154
for (int i = 0; i < 3; i++) {
@@ -149,4 +159,15 @@ public void testWriteSingleValues() throws IOException {
149159
final byte[] actualBytes = outputStream.toByteArray();
150160
assertTrue(Arrays.equals(expectedBytes, actualBytes));
151161
}
162+
163+
public void testWriteBytes() throws IOException {
164+
outputStream = new ByteArrayOutputStream(2);
165+
assertEquals(0, outputStream.size());
166+
outputStream.writeBytes(TEST_ARRAY);
167+
final byte[] actualBytes = outputStream.toByteArray();
168+
assertTrue(Arrays.equals(TEST_ARRAY, actualBytes));
169+
outputStream.writeBytes(new byte[0]);
170+
final byte[] actualBytes2 = outputStream.toByteArray();
171+
assertTrue(Arrays.equals(TEST_ARRAY, actualBytes));
172+
}
152173
}

user/test/com/google/gwt/emultest/java/io/OutputStreamTest.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,16 @@ public void testDefaultBehaviorOfFlush() throws IOException {
6262
// should do nothing (including not throwing an exception).
6363
outputStream.flush();
6464
}
65+
66+
public void testNullOutputStream() throws IOException {
67+
OutputStream nullStream = OutputStream.nullOutputStream();
68+
nullStream.write(42);
69+
nullStream.close();
70+
try {
71+
nullStream.write(1);
72+
fail("Writing to a closed stream should fail.");
73+
} catch (IOException expected) {
74+
// expected
75+
}
76+
}
6577
}

user/test/com/google/gwt/emultest/java/io/WriterTest.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,4 +247,34 @@ public void testWriteNonEmptySubstring() throws IOException {
247247
writer.write(str, 1, 2);
248248
assertTrue(Arrays.equals("ol".toCharArray(), writer.toCharArray()));
249249
}
250+
251+
public void testNullWriter() throws IOException {
252+
Writer nullWriter = Writer.nullWriter();
253+
nullWriter.write(42);
254+
nullWriter.append('a');
255+
nullWriter.write("hola", 1, 2);
256+
nullWriter.close();
257+
// writing to closed stream fails
258+
assertThrows(IOException.class, () -> nullWriter.write(42));
259+
assertThrows(IOException.class, () -> nullWriter.append('a'));
260+
assertThrows(IOException.class, () -> nullWriter.append("hola", 1, 2));
261+
// bounds check takes precedence over closed stream check
262+
assertThrows(IndexOutOfBoundsException.class,
263+
() -> nullWriter.write("hola", 1, 10));
264+
assertThrows(IndexOutOfBoundsException.class,
265+
() -> nullWriter.write(new char[]{'h', 'o', 'l', 'a'}, 1, 10));
266+
}
267+
268+
private void assertThrows(Class<? extends Exception> ex, Throwing toTest) {
269+
try {
270+
toTest.run();
271+
fail("should have failed");
272+
} catch (Exception expected) {
273+
assertEquals(ex, expected.getClass());
274+
}
275+
}
276+
277+
private interface Throwing {
278+
void run() throws Exception;
279+
}
250280
}

0 commit comments

Comments
 (0)