diff --git a/src/java.base/share/classes/java/lang/System.java b/src/java.base/share/classes/java/lang/System.java index 903f6e34e2ee1..c532c1451cd71 100644 --- a/src/java.base/share/classes/java/lang/System.java +++ b/src/java.base/share/classes/java/lang/System.java @@ -116,15 +116,23 @@ private System() { /** * The "standard" input stream. This stream is already - * open and ready to supply input data. Typically this stream + * open and ready to supply input data. This stream * corresponds to keyboard input or another input source specified by - * the host environment or user. In case this stream is wrapped - * in a {@link java.io.InputStreamReader}, {@link Console#charset()} - * should be used for the charset, or consider using - * {@link Console#reader()}. + * the host environment or user. Applications should use the encoding + * specified by the {@link ##stdin.encoding stdin.encoding} property + * to convert input bytes to character data. * - * @see Console#charset() - * @see Console#reader() + * @apiNote + * The typical approach to read character data is to wrap {@code System.in} + * within an {@link java.io.InputStreamReader InputStreamReader} or other object + * that handles character encoding. After this is done, subsequent reading should + * use only the wrapper object; operating directly on {@code System.in} results + * in unspecified behavior. + *

+ * For handling interactive input, consider using {@link Console}. + * + * @see Console + * @see ##stdin.encoding stdin.encoding */ public static final InputStream in = null; @@ -575,17 +583,22 @@ public static native void arraycopy(Object src, int srcPos, * {@systemProperty user.dir} * User's current working directory * {@systemProperty native.encoding} - * Character encoding name derived from the host environment and/or - * the user's settings. Setting this system property has no effect. + * Character encoding name derived from the host environment and + * the user's settings. Setting this system property on the command line + * has no effect. + * {@systemProperty stdin.encoding} + * Character encoding name for {@link System#in System.in}. + * The Java runtime can be started with the system property set to {@code UTF-8}. + * Starting it with the property set to another value results in unspecified behavior. * {@systemProperty stdout.encoding} * Character encoding name for {@link System#out System.out} and * {@link System#console() System.console()}. - * The Java runtime can be started with the system property set to {@code UTF-8}, - * starting it with the property set to another value leads to undefined behavior. + * The Java runtime can be started with the system property set to {@code UTF-8}. + * Starting it with the property set to another value results in unspecified behavior. * {@systemProperty stderr.encoding} * Character encoding name for {@link System#err System.err}. - * The Java runtime can be started with the system property set to {@code UTF-8}, - * starting it with the property set to another value leads to undefined behavior. + * The Java runtime can be started with the system property set to {@code UTF-8}. + * Starting it with the property set to another value results in unspecified behavior. * * *

@@ -639,7 +652,7 @@ public static native void arraycopy(Object src, int srcPos, * the value {@code COMPAT} then the value is replaced with the * value of the {@code native.encoding} property during startup. * Setting the property to a value other than {@code UTF-8} or - * {@code COMPAT} leads to unspecified behavior. + * {@code COMPAT} results in unspecified behavior. * * * diff --git a/src/java.base/share/classes/jdk/internal/util/SystemProps.java b/src/java.base/share/classes/jdk/internal/util/SystemProps.java index 26110a1dab3c9..5760f04831e0e 100644 --- a/src/java.base/share/classes/jdk/internal/util/SystemProps.java +++ b/src/java.base/share/classes/jdk/internal/util/SystemProps.java @@ -88,9 +88,12 @@ public static Map initProperties() { put(props, "file.encoding", nativeEncoding); } - // "stdout/err.encoding", prepared for System.out/err. For compatibility - // purposes, substitute them with "sun.*" if they don't exist. If "sun.*" aren't - // available either, fall back to "native.encoding". + // Encoding properties for stdin, stdout, and stderr. For stdout and stderr, + // check "sun.stdout.encoding" and "sun.stderr.encoding" properties for backward + // compatibility reasons before falling back to the "native.encoding" property. + putIfAbsent(props, "stdin.encoding", + raw.propDefault(Raw._stdin_encoding_NDX)); + putIfAbsent(props, "stdin.encoding", nativeEncoding); putIfAbsent(props, "stdout.encoding", props.getOrDefault("sun.stdout.encoding", raw.propDefault(Raw._stdout_encoding_NDX))); putIfAbsent(props, "stdout.encoding", nativeEncoding); @@ -241,7 +244,8 @@ public static class Raw { @Native private static final int _socksProxyHost_NDX = 1 + _socksNonProxyHosts_NDX; @Native private static final int _socksProxyPort_NDX = 1 + _socksProxyHost_NDX; @Native private static final int _stderr_encoding_NDX = 1 + _socksProxyPort_NDX; - @Native private static final int _stdout_encoding_NDX = 1 + _stderr_encoding_NDX; + @Native private static final int _stdin_encoding_NDX = 1 + _stderr_encoding_NDX; + @Native private static final int _stdout_encoding_NDX = 1 + _stdin_encoding_NDX; @Native private static final int _sun_arch_abi_NDX = 1 + _stdout_encoding_NDX; @Native private static final int _sun_arch_data_model_NDX = 1 + _sun_arch_abi_NDX; @Native private static final int _sun_cpu_endian_NDX = 1 + _sun_arch_data_model_NDX; diff --git a/src/java.base/share/native/libjava/System.c b/src/java.base/share/native/libjava/System.c index b1feaf3dff7a2..725c1e302272c 100644 --- a/src/java.base/share/native/libjava/System.c +++ b/src/java.base/share/native/libjava/System.c @@ -154,6 +154,7 @@ Java_jdk_internal_util_SystemProps_00024Raw_platformProperties(JNIEnv *env, jcla PUTPROP(propArray, _sun_jnu_encoding_NDX, sprops->sun_jnu_encoding); /* encodings for standard streams, may be NULL */ + PUTPROP(propArray, _stdin_encoding_NDX, sprops->stdin_encoding); PUTPROP(propArray, _stdout_encoding_NDX, sprops->stdout_encoding); PUTPROP(propArray, _stderr_encoding_NDX, sprops->stderr_encoding); diff --git a/src/java.base/share/native/libjava/java_props.h b/src/java.base/share/native/libjava/java_props.h index 95fb6d9e7f91a..774a7435e5478 100644 --- a/src/java.base/share/native/libjava/java_props.h +++ b/src/java.base/share/native/libjava/java_props.h @@ -65,6 +65,7 @@ typedef struct { char *display_variant; char *encoding; /* always set non-NULL by platform code */ char *sun_jnu_encoding; /* always set non-NULL by platform code */ + char *stdin_encoding; char *stdout_encoding; char *stderr_encoding; diff --git a/src/java.base/unix/native/libjava/java_props_md.c b/src/java.base/unix/native/libjava/java_props_md.c index 6db307088b019..1d5435d5229c5 100644 --- a/src/java.base/unix/native/libjava/java_props_md.c +++ b/src/java.base/unix/native/libjava/java_props_md.c @@ -464,6 +464,9 @@ GetJavaProperties(JNIEnv *env) sprops.sun_jnu_encoding = sprops.encoding; #endif + if (isatty(STDIN_FILENO) == 1) { + sprops.stdin_encoding = sprops.encoding; + } if (isatty(STDOUT_FILENO) == 1) { sprops.stdout_encoding = sprops.encoding; } diff --git a/src/java.base/windows/native/libjava/java_props_md.c b/src/java.base/windows/native/libjava/java_props_md.c index 275dd3795c500..9495faf81e554 100644 --- a/src/java.base/windows/native/libjava/java_props_md.c +++ b/src/java.base/windows/native/libjava/java_props_md.c @@ -634,7 +634,7 @@ GetJavaProperties(JNIEnv* env) LCID userDefaultUILCID = MAKELCID(userDefaultUILang, SORTIDFROMLCID(userDefaultLCID)); { - HANDLE hStdOutErr; + HANDLE hStdHandle; // Windows UI Language selection list only cares "language" // information of the UI Language. For example, the list @@ -677,14 +677,19 @@ GetJavaProperties(JNIEnv* env) sprops.sun_jnu_encoding = "MS950_HKSCS"; } - hStdOutErr = GetStdHandle(STD_OUTPUT_HANDLE); - if (hStdOutErr != INVALID_HANDLE_VALUE && - GetFileType(hStdOutErr) == FILE_TYPE_CHAR) { + hStdHandle = GetStdHandle(STD_INPUT_HANDLE); + if (hStdHandle != INVALID_HANDLE_VALUE && + GetFileType(hStdHandle) == FILE_TYPE_CHAR) { + sprops.stdin_encoding = getConsoleEncoding(FALSE); + } + hStdHandle = GetStdHandle(STD_OUTPUT_HANDLE); + if (hStdHandle != INVALID_HANDLE_VALUE && + GetFileType(hStdHandle) == FILE_TYPE_CHAR) { sprops.stdout_encoding = getConsoleEncoding(TRUE); } - hStdOutErr = GetStdHandle(STD_ERROR_HANDLE); - if (hStdOutErr != INVALID_HANDLE_VALUE && - GetFileType(hStdOutErr) == FILE_TYPE_CHAR) { + hStdHandle = GetStdHandle(STD_ERROR_HANDLE); + if (hStdHandle != INVALID_HANDLE_VALUE && + GetFileType(hStdHandle) == FILE_TYPE_CHAR) { if (sprops.stdout_encoding != NULL) sprops.stderr_encoding = sprops.stdout_encoding; else diff --git a/test/jdk/java/lang/System/PropertyTest.java b/test/jdk/java/lang/System/PropertyTest.java index ed89e36a8cd93..09b0835fb6ecd 100644 --- a/test/jdk/java/lang/System/PropertyTest.java +++ b/test/jdk/java/lang/System/PropertyTest.java @@ -81,6 +81,7 @@ static Object[][] requiredProperties() { {"java.runtime.version"}, {"java.runtime.name"}, {"native.encoding"}, + {"stdin.encoding"}, {"stdout.encoding"}, {"stderr.encoding"}, };