8276970: Default charset for PrintWriter that wraps PrintStream

Reviewed-by: rriggs, alanb
This commit is contained in:
Naoto Sato 2021-11-18 01:12:12 +00:00
parent 29e552c03a
commit 231fb61aae
4 changed files with 133 additions and 9 deletions

View File

@ -99,7 +99,9 @@ public class OutputStreamWriter extends Writer {
}
/**
* Creates an OutputStreamWriter that uses the default character encoding.
* Creates an OutputStreamWriter that uses the default character encoding, or
* where {@code out} is a {@code PrintStream}, the charset used by the print
* stream.
*
* @param out An OutputStream
* @see Charset#defaultCharset()
@ -107,7 +109,7 @@ public class OutputStreamWriter extends Writer {
public OutputStreamWriter(OutputStream out) {
super(out);
se = StreamEncoder.forOutputStreamWriter(out, this,
Charset.defaultCharset());
out instanceof PrintStream ps ? ps.charset() : Charset.defaultCharset());
}
/**

View File

@ -68,6 +68,7 @@ public class PrintStream extends FilterOutputStream
private final boolean autoFlush;
private boolean trouble = false;
private Formatter formatter;
private final Charset charset;
/**
* Track both the text- and character-output streams, so that their buffers
@ -108,7 +109,8 @@ public class PrintStream extends FilterOutputStream
private PrintStream(boolean autoFlush, OutputStream out) {
super(out);
this.autoFlush = autoFlush;
this.charOut = new OutputStreamWriter(this);
this.charset = out instanceof PrintStream ps ? ps.charset() : Charset.defaultCharset();
this.charOut = new OutputStreamWriter(this, charset);
this.textOut = new BufferedWriter(charOut);
}
@ -124,7 +126,8 @@ public class PrintStream extends FilterOutputStream
/**
* Creates a new print stream, without automatic line flushing, with the
* specified OutputStream. Characters written to the stream are converted
* to bytes using the default charset.
* to bytes using the default charset, or where {@code out} is a
* {@code PrintStream}, the charset used by the print stream.
*
* @param out The output stream to which values and objects will be
* printed
@ -139,7 +142,8 @@ public class PrintStream extends FilterOutputStream
/**
* Creates a new print stream, with the specified OutputStream and line
* flushing. Characters written to the stream are converted to bytes using
* the default charset.
* the default charset, or where {@code out} is a {@code PrintStream},
* the charset used by the print stream.
*
* @param out The output stream to which values and objects will be
* printed
@ -201,6 +205,7 @@ public class PrintStream extends FilterOutputStream
this.autoFlush = autoFlush;
this.charOut = new OutputStreamWriter(this, charset);
this.textOut = new BufferedWriter(charOut);
this.charset = charset;
}
/**
@ -1374,4 +1379,12 @@ public class PrintStream extends FilterOutputStream
return this;
}
/**
* {@return the charset used in this {@code PrintStream} instance}
*
* @since 18
*/
public Charset charset() {
return charset;
}
}

View File

@ -118,7 +118,8 @@ public class PrintWriter extends Writer {
* Creates a new PrintWriter, without automatic line flushing, from an
* existing OutputStream. This convenience constructor creates the
* necessary intermediate OutputStreamWriter, which will convert characters
* into bytes using the default charset.
* into bytes using the default charset, or where {@code out} is a
* {@code PrintStream}, the charset used by the print stream.
*
* @param out An output stream
*
@ -132,8 +133,9 @@ public class PrintWriter extends Writer {
/**
* Creates a new PrintWriter from an existing OutputStream. This
* convenience constructor creates the necessary intermediate
* OutputStreamWriter, which will convert characters into bytes using the
* default charset.
* OutputStreamWriter, which will convert characters into bytes using
* the default charset, or where {@code out} is a {@code PrintStream},
* the charset used by the print stream.
*
* @param out An output stream
* @param autoFlush A boolean; if true, the {@code println},
@ -144,7 +146,7 @@ public class PrintWriter extends Writer {
* @see Charset#defaultCharset()
*/
public PrintWriter(OutputStream out, boolean autoFlush) {
this(out, autoFlush, Charset.defaultCharset());
this(out, autoFlush, out instanceof PrintStream ps ? ps.charset() : Charset.defaultCharset());
}
/**

View File

@ -0,0 +1,107 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
/**
* @test
* @bug 8276970
* @summary Test to verify the charset in PrintStream is inherited
* in the OutputStreamWriter/PrintWriter
* @run testng InheritEncodingTest
*/
@Test
public class InheritEncodingTest {
private static final String testString = "\u00e9\u3042"; // "éあ"
@DataProvider
public Object[][] encodings() {
return new Object[][]{
{StandardCharsets.ISO_8859_1},
{StandardCharsets.US_ASCII},
{StandardCharsets.UTF_8},
{StandardCharsets.UTF_16},
{StandardCharsets.UTF_16BE},
{StandardCharsets.UTF_16LE},
};
}
@Test (dataProvider = "encodings")
public void testOutputStreamWriter(Charset stdCharset) throws IOException {
var ba = new ByteArrayOutputStream();
var ps = new PrintStream(ba, true, stdCharset);
var expected = new String(testString.getBytes(stdCharset), stdCharset);
// tests OutputStreamWriter's encoding explicitly
var osw = new OutputStreamWriter(ps);
assertEquals(Charset.forName(osw.getEncoding()), stdCharset);
// tests roundtrip result
osw.write(testString);
osw.flush();
var result = ba.toString(stdCharset);
assertEquals(result, expected);
}
@Test (dataProvider = "encodings")
public void testPrintWriter(Charset stdCharset) throws IOException {
var ba = new ByteArrayOutputStream();
var ps = new PrintStream(ba, true, stdCharset);
var expected = new String(testString.getBytes(stdCharset), stdCharset);
// tests roundtrip result
var pw = new PrintWriter(ps);
pw.write(testString);
pw.flush();
var result = ba.toString(stdCharset);
assertEquals(result, expected);
}
@Test (dataProvider = "encodings")
public void testPrintStream(Charset stdCharset) throws IOException {
var ba = new ByteArrayOutputStream();
var ps = new PrintStream(ba, true, stdCharset);
var expected = new String(testString.getBytes(stdCharset), stdCharset);
// tests PrintStream's charset explicitly
var psWrapper = new PrintStream(ps);
assertEquals(psWrapper.charset(), stdCharset);
// tests roundtrip result
psWrapper.print(testString);
psWrapper.flush();
var result = ba.toString(stdCharset);
assertEquals(result, expected);
}
}