Skip to content

Commit

Permalink
Merge pull request #15154 from pshipton/stdoutenc
Browse files Browse the repository at this point in the history
Add jdk19 support for stdout.encoding and stderr.encoding
  • Loading branch information
keithc-ca committed Jun 3, 2022
2 parents 6335127 + 0488147 commit 6814cc0
Show file tree
Hide file tree
Showing 4 changed files with 173 additions and 51 deletions.
25 changes: 1 addition & 24 deletions jcl/src/java.base/share/classes/java/lang/J9VMInternals.java
Original file line number Diff line number Diff line change
Expand Up @@ -101,30 +101,7 @@ static void threadCompleteInitialization() {
/*[ENDIF] Sidecar18-SE-OpenJ9 | (JAVA_SPEC_VERSION > 8) */

/*[IF JAVA_SPEC_VERSION >= 11] */
/* Although file.encoding is used to set the default Charset, some Charset's are not available
* in the java.base module and so are not used at startup. There are additional Charset's in the
* jdk.charsets module, which is only loaded later. This means the default Charset may not be the
* same as file.encoding. Now that all modules and Charset's are available, check if the desired
* encodings can be used for System.err and System.out.
*/
Properties props = System.internalGetProperties();
// If the sun.stderr.encoding was already set in System, don't change the encoding
if (!System.hasSetErrEncoding()) {
Charset stderrCharset = System.getCharset(props.getProperty("sun.stderr.encoding"), true); //$NON-NLS-1$
if (stderrCharset != null) {
System.err.flush();
System.setErr(System.createConsole(FileDescriptor.err, stderrCharset));
}
}

// If the sun.stdout.encoding was already set in System, don't change the encoding
if (!System.hasSetOutEncoding()) {
Charset stdoutCharset = System.getCharset(props.getProperty("sun.stdout.encoding"), true); //$NON-NLS-1$
if (stdoutCharset != null) {
System.out.flush();
System.setOut(System.createConsole(FileDescriptor.out, stdoutCharset));
}
}
System.finalizeConsoleEncoding();
/*[ENDIF] JAVA_SPEC_VERSION >= 11 */
}

Expand Down
118 changes: 91 additions & 27 deletions jcl/src/java.base/share/classes/java/lang/System.java
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,15 @@ public final class System {
private static boolean hasSetOutEncoding;
private static String consoleDefaultEncoding;
/* The consoleDefaultCharset is different from the default console encoding when the encoding
* doesn't exist, or isn't available at startup. Some Charset's are not available in the
* java.base module and so are not used at startup.
* doesn't exist, or isn't available at startup. Some character sets are not available in the
* java.base module, there are more in the jdk.charsets module, and so are not used at startup.
*/
private static Charset consoleDefaultCharset;
/*[ENDIF] JAVA_SPEC_VERSION >= 11 */
/*[IF JAVA_SPEC_VERSION >= 19]*/
private static String stdoutProp;
private static String stderrProp;
/*[ENDIF] JAVA_SPEC_VERSION >= 19 */

/*[IF Sidecar19-SE]*/
static java.lang.ModuleLayer bootLayer;
Expand Down Expand Up @@ -190,7 +194,12 @@ public final class System {
* consoleDefaultCharset must be initialized before calling.
* consoleDefaultEncoding must be initialized before calling with fallback set to true.
*/
static Charset getCharset(String primary, boolean fallback) {
static Charset getCharset(boolean isStdout, boolean fallback) {
/*[IF JAVA_SPEC_VERSION >= 19]*/
String primary = isStdout ? stdoutProp : stderrProp;
/*[ELSE] JAVA_SPEC_VERSION >= 19 */
String primary = internalGetProperties().getProperty(isStdout ? "sun.stdout.encoding" : "sun.stderr.encoding"); //$NON-NLS-1$ //$NON-NLS-2$
/*[ENDIF] JAVA_SPEC_VERSION >= 19 */
if (primary != null) {
try {
Charset newCharset = Charset.forName(primary);
Expand Down Expand Up @@ -218,20 +227,6 @@ static Charset getCharset(String primary, boolean fallback) {
return null;
}

/*
* Return if sun.stderr.encoding was used.
*/
static boolean hasSetErrEncoding() {
return hasSetErrEncoding;
}

/*
* Return if sun.stdout.encoding was used.
*/
static boolean hasSetOutEncoding() {
return hasSetOutEncoding;
}

/*
* Return the appropriate System console using the requested Charset.
* If the Charset is null use the default console Charset.
Expand All @@ -241,12 +236,58 @@ static boolean hasSetOutEncoding() {
static PrintStream createConsole(FileDescriptor desc, Charset charset) {
BufferedOutputStream bufStream = new BufferedOutputStream(new FileOutputStream(desc));
Charset consoleCharset = charset == null ? consoleDefaultCharset : charset;

/*[IF JAVA_SPEC_VERSION >= 19]*/
Properties props = internalGetProperties();
// If the user didn't set the encoding property, set it now.
if (FileDescriptor.out == desc) {
if (null == stdoutProp) {
props.put("stdout.encoding", consoleCharset.name()); //$NON-NLS-1$
}
} else if (FileDescriptor.err == desc) {
if (null == stderrProp) {
props.put("stderr.encoding", consoleCharset.name()); //$NON-NLS-1$
}
}
/*[ENDIF] JAVA_SPEC_VERSION >= 19 */

/*[IF PLATFORM-mz31 | PLATFORM-mz64]*/
return ConsolePrintStream.localize(bufStream, true, consoleCharset);
/*[ELSE]*/
return new PrintStream(bufStream, true, consoleCharset);
/*[ENDIF] PLATFORM-mz31 | PLATFORM-mz64 */
}

static void finalizeConsoleEncoding() {
/* Some character sets are not available in the java.base module and so are not used at startup. There
* are additional character sets in the jdk.charsets module, which is only loaded later. This means the
* default character set may not be the same as the desired encoding. When all modules and character sets
* are available, check if the desired encodings can be used for System.err and System.out.
*/
// If the encoding property was already set, don't change the encoding.
if (!hasSetErrEncoding) {
Charset stderrCharset = getCharset(false, true);
if (stderrCharset != null) {
err.flush();
setErr(createConsole(FileDescriptor.err, stderrCharset));
}
}

// If the encoding property was already set, don't change the encoding.
if (!hasSetOutEncoding) {
Charset stdoutCharset = getCharset(true, true);
if (stdoutCharset != null) {
out.flush();
setOut(createConsole(FileDescriptor.out, stdoutCharset));
}
}

/*[IF JAVA_SPEC_VERSION >= 19]*/
// Cache the final system property values so they can be restored if ensureProperties(false) is called.
stdoutProp = systemProperties.getProperty("stdout.encoding"); //$NON-NLS-1$
stderrProp = systemProperties.getProperty("stderr.encoding"); //$NON-NLS-1$
/*[ENDIF] JAVA_SPEC_VERSION >= 19 */
}
/*[ELSE]*/
/*[IF Sidecar18-SE-OpenJ9]*/
/*
Expand Down Expand Up @@ -365,8 +406,8 @@ static void afterClinitInitialization() {
/*[ENDIF] PLATFORM-mz31|PLATFORM-mz64 */
/*[ENDIF] JAVA_SPEC_VERSION >= 18 */
/* consoleDefaultCharset must be initialized before calling getCharset() */
Charset stdoutCharset = getCharset(props.getProperty("sun.stdout.encoding"), false); //$NON-NLS-1$
Charset stderrCharset = getCharset(props.getProperty("sun.stderr.encoding"), false); //$NON-NLS-1$
Charset stdoutCharset = getCharset(true, false);
Charset stderrCharset = getCharset(false, false);
/*[ELSE] JAVA_SPEC_VERSION >= 11 */
Charset consoleCharset = Charset.defaultCharset();
String stdoutCharset = getCharsetName(props.getProperty("sun.stdout.encoding"), consoleCharset); //$NON-NLS-1$
Expand All @@ -376,12 +417,8 @@ static void afterClinitInitialization() {

/*[IF Sidecar18-SE-OpenJ9]*/
/*[IF JAVA_SPEC_VERSION >= 11]*/
if (stderrCharset != null) {
hasSetErrEncoding = true;
}
if (stdoutCharset != null) {
hasSetOutEncoding = true;
}
hasSetErrEncoding = stderrCharset != null;
hasSetOutEncoding = stdoutCharset != null;
/* consoleDefaultCharset must be initialized before calling createConsole() */
/*[ENDIF] JAVA_SPEC_VERSION >= 11 */
/*[IF JAVA_SPEC_VERSION >= 17] */
Expand All @@ -400,7 +437,7 @@ static void afterClinitInitialization() {
setErr(createConsole(FileDescriptor.err));
setOut(createConsole(FileDescriptor.out));
/*[ENDIF] Sidecar18-SE-OpenJ9 */

/*[IF JAVA_SPEC_VERSION >= 17] */
setSMCallers = Collections.synchronizedMap(new WeakHashMap<>());
/*[ENDIF] JAVA_SPEC_VERSION >= 17 */
Expand Down Expand Up @@ -654,6 +691,33 @@ private static void ensureProperties(boolean isInitialization) {
initializedProperties.put("native.encoding", platformEncoding); //$NON-NLS-1$
/*[ENDIF] JAVA_SPEC_VERSION >= 17 */

/*[IF JAVA_SPEC_VERSION >= 19]*/
if (null != stdoutProp) {
// Reinitialize required properties if ensureProperties(false) is called.
initializedProperties.put("stdout.encoding", stdoutProp); //$NON-NLS-1$
} else {
stdoutProp = initializedProperties.get("stdout.encoding"); //$NON-NLS-1$
if (null == stdoutProp) {
stdoutProp = initializedProperties.get("sun.stdout.encoding"); //$NON-NLS-1$
if (null != stdoutProp) {
initializedProperties.put("stdout.encoding", stdoutProp); //$NON-NLS-1$
}
}
}
if (null != stderrProp) {
// Reinitialize required properties if ensureProperties(false) is called.
initializedProperties.put("stderr.encoding", stderrProp); //$NON-NLS-1$
} else {
stderrProp = initializedProperties.get("stderr.encoding");
if (null == stderrProp) { //$NON-NLS-1$
stderrProp = initializedProperties.get("sun.stderr.encoding"); //$NON-NLS-1$
if (null != stderrProp) {
initializedProperties.put("stderr.encoding", stderrProp); //$NON-NLS-1$
}
}
}
/*[ENDIF] JAVA_SPEC_VERSION >= 19 */

/* java.lang.VersionProps.init() eventually calls into System.setProperty() where propertiesInitialized needs to be true */
propertiesInitialized = true;

Expand Down Expand Up @@ -1166,7 +1230,7 @@ public static void setSecurityManager(final SecurityManager s) {
// ignore any potential exceptions
}
}

try {
/*[PR 97686] Preload the policy permission */
AccessController.doPrivileged(new PrivilegedAction<Void>() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>

<!--
Copyright (c) 2021, 2022 IBM Corp. and others
This program and the accompanying materials are made available under
the terms of the Eclipse Public License 2.0 which accompanies this
distribution and is available at https://www.eclipse.org/legal/epl-2.0/
or the Apache License, Version 2.0 which accompanies this distribution and
is available at https://www.apache.org/licenses/LICENSE-2.0.
This Source Code may also be made available under the following
Secondary Licenses when the conditions for such availability set
forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
General Public License, version 2 with the GNU Classpath
Exception [1] and GNU General Public License, version 2 with the
OpenJDK Assembly Exception [2].
[1] https://www.gnu.org/software/classpath/license.html
[2] http://openjdk.java.net/legal/assembly-exception.html
SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
-->
<!DOCTYPE suite SYSTEM "cmdlinetester.dtd">

<suite id="J9 Command-Line Option Tests" timeout="180">
<variable name="CP" value="-cp $Q$$JARPATH$$Q$" />
<variable name="TARGET" value="GetConsoleCharset" />
<variable name="OPENS" value="--add-opens=java.base/java.io=ALL-UNNAMED"/>
<variable name="DEFAULT_ENCODING_PROP" value="file.encoding" />
<variable name="DEFAULT_ENCODING_PROP" value="ibm.system.encoding" platforms="zos.*" />
<!-- Use an encoding supported by Java 8 and in the java.base module -->
<variable name="ENCODING1" value="ISO8859_2" />
<!-- Use an encoding supported by Java 8 and in the jdk.charsets module -->
<variable name="ENCODING2" value="Cp948" />

<test id="sun.stdout.encoding $ENCODING1$">
<command>$EXE$ $OPENS$ $CP$ -D$DEFAULT_ENCODING_PROP$=$ENCODING2$ -Dstdout.encoding=$ENCODING1$ $TARGET$ out $ENCODING1$</command>
<return type="success" value="0" />
</test>

<test id="sun.stderr.encoding $ENCODING1$">
<command>$EXE$ $OPENS$ $CP$ -D$DEFAULT_ENCODING_PROP$=$ENCODING2$ -Dstderr.encoding=$ENCODING1$ $TARGET$ err $ENCODING1$</command>
<return type="success" value="0" />
</test>

<test id="sun.stdout.encoding $ENCODING2$">
<command>$EXE$ $OPENS$ $CP$ -Dstdout.encoding=$ENCODING2$ $TARGET$ out $ENCODING2$</command>
<return type="success" value="0" />
</test>

<test id="sun.stderr.encoding $ENCODING2$">
<command>$EXE$ $OPENS$ $CP$ -Dstderr.encoding=$ENCODING2$ $TARGET$ err $ENCODING2$</command>
<return type="success" value="0" />
</test>

</suite>
24 changes: 24 additions & 0 deletions test/functional/cmdLineTests/cmdLineTest_J9tests/playlist.xml
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,30 @@
<impl>openj9</impl>
</impls>
</test>
<test>
<testCaseName>cmdLineTest_J9test_console19</testCaseName>
<command>$(JAVA_COMMAND) $(JVM_OPTIONS) \
-DJARPATH=$(Q)$(TEST_RESROOT)$(D)cmdLineTest_J9tests.jar$(Q) -DJDK_VERSION=$(JDK_VERSION) \
-DJVMLIBPATH=$(Q)$(J9VM_PATH)$(Q) \
-DTESTDIR=$(Q)$(TEST_RESROOT)$(Q) -DRESJAR=$(CMDLINETESTER_RESJAR) -DEXE=$(SQ)$(JAVA_COMMAND) $(JVM_OPTIONS) -Xdump$(SQ) \
-jar $(CMDLINETESTER_JAR) \
-config $(Q)$(TEST_RESROOT)$(D)j9tests_console19.xml$(Q) \
-xids all,$(PLATFORM) -plats all,$(PLATFORM) -xlist $(Q)$(TEST_RESROOT)$(D)j9tests_exclude.xml$(Q) \
-explainExcludes -nonZeroExitWhenError; \
$(TEST_STATUS)</command>
<levels>
<level>extended</level>
</levels>
<groups>
<group>functional</group>
</groups>
<versions>
<version>19+</version>
</versions>
<impls>
<impl>openj9</impl>
</impls>
</test>
<test>
<testCaseName>cmdLineTest_J9test_console</testCaseName>
<command>$(JAVA_COMMAND) $(JVM_OPTIONS) \
Expand Down

0 comments on commit 6814cc0

Please sign in to comment.