Java 程序在 jpackage 时使用了错误的语言环境

Java program uses wrong locale when jpackaged

我正在解析表示德语风格数字的字符串(即十进制逗号和用于对千位进行分组的可选句号),例如“2.804,13”;这只是根据我想要的 Locale:

使用 DecimalFormat 完成的
package loc_test;

import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Locale;

public class ParseNumbers {
    static final DecimalFormat df = (DecimalFormat) NumberFormat.getNumberInstance(Locale.GERMANY);

    public static void main(String[] args) throws Exception {
        for (String s : new String[] { "2.815,53", "2815,53" }) {
            System.out.println(String.format("%s \t-> %s", s, df.parse(s)));
        }
    }
}

这给出了所需的输出,例如,编译时和从命令行运行:

2.815,53        -> 2815.53
2815,53         -> 2815.53

但是,当我将其捆绑为 jpackage 图像(./gradlew jpackageImage 使用 Gradle 和 Badass Runtime Plugin)和 运行 生成的二进制文件时,输出似乎表明使用了错误的语言环境:

2.815,53    -> 2.815
2815,53     -> 281553

我已经尝试了一些东西(没有成功),问题似乎不在代码本身:

  1. main 中添加了 Locale.setDefault(Locale.GERMANY)Locale.getDefault() 将显示德语语言环境,但没有任何效果。
  2. 通过Java 命令行参数明确设置-Duser.country=DE-Duser.language=deSystem.getProperty(...) 显示预期值,但同样没有效果。 (此外,从命令行,它也适用于将这些设置为系统默认值。)
  3. -Djava.locale.providers=COMPAT,CLDR,SPI 添加到 jpackage Java 命令行参数(来自 this thread)。同样,我可以从 main 验证 属性 设置是否正确,但这没有区别。 (而且似乎是早期 Java 版本的问题。)

我首先看到问题是使用 Java 16 和 Gradle 7.2;并且在 Java 17 和 Gradle 7.3 更新后仍然存在。这个问题在英语 Linux 系统和德语 Windows 机器上都发生过。

--infojpackageImage 命令一起使用,Gradle 告诉我它正在使用哪个 JDK:

Starting process 'command '.../.gradle/jdks/jdk-17+35/bin/jpackage''. Working directory: .../LocTest/app Command: .../.gradle/jdks/jdk-17+35/bin/jpackage --type app-image --input .../LocTest/app/build/install/app/lib --main-jar app.jar --main-class LocTest.App --dest .../LocTest/app/build/jpackage --name app --runtime-image .../LocTest/app/build/jre --java-options -Duser.country=DE --java-options -Duser.language=de --java-options -Djava.locale.providers=COMPAT,CLDR,SPI

当我使用 .gradle/jdks/jdk-17+35/bin/java 到 运行 class 时,即 运行:

~/.gradle/jdks/jdk-17+35/bin/java -cp app/build/classes/java/main loc_test.App`

这样,不会出现问题;数字是正确的。

但是,当我使用与 jpackage 图像捆绑在一起的(假设相同的)JRE 时,确实 出现了问题,即,我得到了 错误的 数字使用:

./app/build/jpackage/app/lib/runtime/bin/java -cp app/build/classes/java/main/ loc_test.App

为什么 java 在打包时会忽略语言环境? 我在这里遗漏了什么,或者这可能是 jpackage 或插件中的错误,或者是 Java 版本本身的错误?

整个Gradle示例项目(非常小)can be found at Github

检查您的 运行time 图像中包含哪些模块。

例如当我 运行 java --list-modules 在 JDK 17 我注意到这个模块:

jdk.localedata

我不知道这是否是必需的,但我敢打赌,除非特别要求,否则 jpackage 不会包含该模块。

运行 ./app/build/jpackage/app/lib/runtime/bin/java --list-modules 并与 ~/.gradle/jdks/jdk-17+35/bin/java --list-modules 进行比较以确认。然后考虑用 jlink 制作一张包含 jdk.localedata 的图像,如果缺少它来检验这个假设。