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
我已经尝试了一些东西(没有成功),问题似乎不在代码本身:
- 在
main
中添加了 Locale.setDefault(Locale.GERMANY)
。 Locale.getDefault()
将显示德语语言环境,但没有任何效果。
- 通过Java 命令行参数明确设置
-Duser.country=DE
和-Duser.language=de
。 System.getProperty(...)
显示预期值,但同样没有效果。 (此外,从命令行,它也适用于将这些设置为系统默认值。)
- 将
-Djava.locale.providers=COMPAT,CLDR,SPI
添加到 jpackage Java 命令行参数(来自 this thread)。同样,我可以从 main
验证 属性 设置是否正确,但这没有区别。 (而且似乎是早期 Java 版本的问题。)
我首先看到问题是使用 Java 16 和 Gradle 7.2;并且在 Java 17 和 Gradle 7.3 更新后仍然存在。这个问题在英语 Linux 系统和德语 Windows 机器上都发生过。
将 --info
与 jpackageImage
命令一起使用,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
的图像,如果缺少它来检验这个假设。
我正在解析表示德语风格数字的字符串(即十进制逗号和用于对千位进行分组的可选句号),例如“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
我已经尝试了一些东西(没有成功),问题似乎不在代码本身:
- 在
main
中添加了Locale.setDefault(Locale.GERMANY)
。Locale.getDefault()
将显示德语语言环境,但没有任何效果。 - 通过Java 命令行参数明确设置
-Duser.country=DE
和-Duser.language=de
。System.getProperty(...)
显示预期值,但同样没有效果。 (此外,从命令行,它也适用于将这些设置为系统默认值。) - 将
-Djava.locale.providers=COMPAT,CLDR,SPI
添加到 jpackage Java 命令行参数(来自 this thread)。同样,我可以从main
验证 属性 设置是否正确,但这没有区别。 (而且似乎是早期 Java 版本的问题。)
我首先看到问题是使用 Java 16 和 Gradle 7.2;并且在 Java 17 和 Gradle 7.3 更新后仍然存在。这个问题在英语 Linux 系统和德语 Windows 机器上都发生过。
将 --info
与 jpackageImage
命令一起使用,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
的图像,如果缺少它来检验这个假设。