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"},
};