Skip to content

Property sun.stdout.encoding is undefined in recent Java versions#407

Open
wfouche wants to merge 8 commits intojython:masterfrom
wfouche:dev/console-utf8
Open

Property sun.stdout.encoding is undefined in recent Java versions#407
wfouche wants to merge 8 commits intojython:masterfrom
wfouche:dev/console-utf8

Conversation

@wfouche
Copy link
Member

@wfouche wfouche commented Dec 15, 2025

Tested with script

C:\...> "activate JDK 8"
C:\...> ant installer

C:\...> chcp 65001
Active code page: 65001

C:\...> java -jar dist\jython-standalone.jar
>>> unicode_string = u"Hello World: \u2764"
>>> print unicode_string
Hello World: ❤

C:\...> "activate JDK 25.0.1"

C:\...> java -jar dist\jython-standalone.jar
>>> unicode_string = u"Hello World: \u2764"
>>> print unicode_string
Hello World: ❤

on Java 8 and 25.

Fixes #404

String output = Py.getCommandResultWindows("chcp");
String output = Py.getCommandResultWindows("chcp.com");
/*
* The output will be like "Active code page: 850" or maybe "Aktive Codepage: 1252." or
Copy link
Member

@jeff5 jeff5 Dec 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm explaining why the only reliable bit of the message is the number. ISTR this one is German.

Ja. So stimmt es. https://www.mikrocontroller.net/topic/561065

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverted back to Aktive.

@jeff5
Copy link
Member

jeff5 commented Dec 15, 2025

As I commented on the original issue, testing console handling is hard because our CI doesn't really exercise it. So it's down to conscientious local testing.

encoding = props.getProperty("sun.stdout.encoding");
if (encoding != null) {
// Windows: these versions of Java return "cp65001" for UTF-8
if (encoding.equals("cp65001")) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we only bother with this inside the "if it's Windows" clause?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, good catch. Fixed.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Fixed.

if (os != null && os.startsWith("Windows")) {
// Go via the Windows code page built-in command "chcp".
String output = Py.getCommandResultWindows("chcp");
String output = Py.getCommandResultWindows("chcp.com");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why change?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When running chcp from Git-Bash on Windows, it cannot find "chcp" and one has to specify the full name which is "chcp.com". I thought Jython might experience the same issue, but it does not. So will revert this change.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

C:\> where chcp
C:\Windows\System32\chcp.com

@wfouche
Copy link
Member Author

wfouche commented Dec 16, 2025

@jeff5 , the following code fragment is unlikely to be executed on Windows given that stdout.encoding and sun.stdout.encoding seems to cover all bases.

        if (isWindows) {
            // Go via the Windows code page built-in command "chcp".
            String output = Py.getCommandResultWindows("chcp");
            /*
             * The output will be like "Active code page: 850" or maybe "Aktive Codepage: 1252." or
             * "활성 코드 페이지: 949". Assume the first number with 2 or more digits is the code page.
             */
            final Pattern DIGITS_PATTERN = Pattern.compile("[1-9]\\d+");
            Matcher matcher = DIGITS_PATTERN.matcher(output);
            if (matcher.find()) {
                encoding = "cp".concat(output.substring(matcher.start(), matcher.end()));
                if (encoding.equals("cp65001")) {
                    encoding = "utf-8";
                }
                return encoding;
            }

        }

@wfouche
Copy link
Member Author

wfouche commented Dec 16, 2025

@jeff5 , I installed SDKMAN using Git-Bash on Windows, and this makes it a lot easier to do Jython console testing using different versions of Java. With SDKMAN I can easily install and switch between diffrent JDK versions.

First install scoop - https://scoop.sh/

Then run these commands to install Git/Bash, curl, zip and unzip

  • scoop install git
  • scoop install curl zip unzip

Lastly, install SDKMAN

Now one can start bash.exe from inside the Jython project folder

cd IdeaProjects\jython

C:\...\IdeaProjects\jython> bash.exe
$ sdk install java 8.0.472-tem
$ sdk install java 25.0.1-tem
$ sdk use java 8.0.472-tem
$ ant installer
$ java -version
openjdk version "1.8.0_472"
OpenJDK Runtime Environment (Temurin)(build 1.8.0_472-b08)
OpenJDK 64-Bit Server VM (Temurin)(build 25.472-b08, mixed mode)
$ java -jar dist/jython-standalone.jar
Jython 2.7.5a1-SNAPSHOT (heads/dev/console-utf8:545df7b60, Dec 16 2025, 09:34:43)
[OpenJDK 64-Bit Server VM (Temurin)] on java1.8.0_472
Type "help", "copyright", "credits" or "license" for more information.
>>>
$ sdk use java 25.0.1-tem
$ java -version
openjdk version "25.0.1" 2025-10-21 LTS
OpenJDK Runtime Environment Temurin-25.0.1+8 (build 25.0.1+8-LTS)
OpenJDK 64-Bit Server VM Temurin-25.0.1+8 (build 25.0.1+8-LTS, mixed mode, sharing)
$ java -jar dist/jython-standalone.jar
Jython 2.7.5a1-SNAPSHOT (heads/dev/console-utf8:545df7b60, Dec 16 2025, 09:34:43)
[OpenJDK 64-Bit Server VM (Eclipse Adoptium)] on java25.0.1
Type "help", "copyright", "credits" or "license" for more information.
>>>
$ exit
C:\...\IdeaProjects\jython>

Bash is just a different Windows shell, so when Jython runs it still runs as it normally would as a Windows process.

Don't you think this would make a good addition to the README.md file?

@wfouche
Copy link
Member Author

wfouche commented Dec 18, 2025

Results of tests performanced on Linux, MacOS and Windows. We can see that for Java 21 and higher, property stdout.encoding is always defined. Older versions of Java don't define property stdout.encoding, and may or may not defined property sun.stdout.encoding.

Linux

  • java.version = 1.8.0_462, sun.stdout.encoding = null, stdout.encoding = null
  • java.version = 11.0.29, sun.stdout.encoding = null, stdout.encoding = null
  • java.version = 17.0.16, sun.stdout.encoding = UTF-8, stdout.encoding = null
  • java.version = 21.0.9, sun.stdout.encoding = null, stdout.encoding = UTF-8
  • java.version = 25, sun.stdout.encoding = null, stdout.encoding = UTF-8

MacOS

  • java.version = 1.8.0_472, sun.stdout.encoding = null, stdout.encoding = null
  • java.version = 11.0.29, sun.stdout.encoding = null, stdout.encoding = null
  • java.version = 17.0.17, sun.stdout.encoding = UTF-8, stdout.encoding = null
  • java.version = 21.0.9, sun.stdout.encoding = null, stdout.encoding = UTF-8
  • java.version = 25.0.1, sun.stdout.encoding = null, stdout.encoding = UTF-8

Windows

  • java.version = 1.8.0_472, sun.stdout.encoding = cp65001, stdout.encoding = null
  • java.version = 11.0.29, sun.stdout.encoding = UTF-8, stdout.encoding = null
  • java.version = 17.0.17, sun.stdout.encoding = UTF-8, stdout.encoding = null
  • java.version = 21.0.9, sun.stdout.encoding = null, stdout.encoding = UTF-8
  • java.version = 25.0.1, sun.stdout.encoding = null, stdout.encoding = UTF-8

test.cmd

call jbang run --java 8 test.kt
call jbang run --java 11 test.kt
call jbang run --java 17 test.kt
call jbang run --java 21 test.kt
call jbang run --java 25 test.kt

test.sh

jbang run --java 8 test.kt
jbang run --java 11 test.kt
jbang run --java 17 test.kt
jbang run --java 21 test.kt
jbang run --java 25 test.kt

test.kt

val javaVersion = System.getProperty("java.version") ?: "null"
val sun_stdout_encoding = System.getProperty("sun.stdout.encoding") ?: "null"
val stdout_encoding = System.getProperty("stdout.encoding") ?: "null"

fun main() {
    print("java.version = " + javaVersion)
    print(", sun.stdout.encoding = " + sun_stdout_encoding)
    println(", stdout.encoding = " + stdout_encoding)
}

@wfouche
Copy link
Member Author

wfouche commented Dec 18, 2025

@jeff5 , testing has been completed. Please review once more.

Could we eventually release this as Jython 2.7.5?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Windows code page 65001 (UTF-8) not supported by Jython

2 participants

Comments