Skip to content

8355522: Remove the java.locale.useOldISOCodes system property #26419

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 8 additions & 30 deletions src/java.base/share/classes/java/util/Locale.java
Original file line number Diff line number Diff line change
Expand Up @@ -528,34 +528,13 @@
*
* <h3><a id="legacy_language_codes">Legacy language codes</a></h3>
*
* <p>Locale's constructors have always converted three language codes to
* their earlier, obsoleted forms: {@code he} maps to {@code iw},
* {@code yi} maps to {@code ji}, and {@code id} maps to
* {@code in}. Since Java SE 17, this is no longer the case. Each
* language maps to its new form; {@code iw} maps to {@code he}, {@code ji}
* maps to {@code yi}, and {@code in} maps to {@code id}.
*
* <p>For backwards compatible behavior, the system property
* {@systemProperty java.locale.useOldISOCodes} reverts the behavior
* back to that of before Java SE 17. If the system property is set to
* {@code true}, those three current language codes are mapped to their
* backward compatible forms. The property is only read at Java runtime
* startup and subsequent calls to {@code System.setProperty()} will
* have no effect. <b>As of Java SE 25, the use of the
* {@code java.locale.useOldISOCodes} system property is deprecated.
* This backwards compatible behavior will be removed in a future release
* of the JDK.</b>
*
* <p>The APIs added in Java SE 7 map between the old and new language codes,
* maintaining the mapped codes internal to Locale (so that
* {@code getLanguage} and {@code toString} reflect the mapped
* code, which depends on the {@code java.locale.useOldISOCodes} system
* property), but using the new codes in the BCP 47 language tag APIs (so
* that {@code toLanguageTag} reflects the new one). This
* preserves the equivalence between Locales no matter which code or
* API is used to construct them. Java's default resource bundle
* lookup mechanism also implements this mapping, so that resources
* can be named using either convention, see {@link ResourceBundle.Control}.
* <p>For compatibility, a {@code Locale} created with one of the
* three obsolete language codes, {@code iw}, {@code ji}, or {@code in},
* will map the language to its modern equivalent, {@code he}, {@code yi},
* or {@code id}, respectively.
* <p>The default resource bundle lookup mechanism also implements
* this mapping, so that resources can be named using either convention,
* see {@link ResourceBundle.Control}.
*
* @spec https://www.rfc-editor.org/info/rfc4647
* RFC 4647: Matching of Language Tags
Expand Down Expand Up @@ -2517,8 +2496,7 @@ private Object readResolve() throws java.io.ObjectStreamException {

private static String convertOldISOCodes(String language) {
// we accept both the old and the new ISO codes for the languages whose ISO
// codes have changed, but we always store the NEW code, unless the property
// java.locale.useOldISOCodes is set to "true"
// codes have changed, but we always store the NEW code
return BaseLocale.convertOldISOCodes(LocaleUtils.toLowerString(language).intern());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ public final class StaticProperty {
private static final String STDOUT_ENCODING;
private static final String SUN_JNU_ENCODING;
private static final String JAVA_PROPERTIES_DATE;
private static final String JAVA_LOCALE_USE_OLD_ISO_CODES;
private static final String OS_NAME;
private static final String OS_ARCH;
private static final String OS_VERSION;
Expand Down Expand Up @@ -94,7 +93,6 @@ private StaticProperty() {}
STDOUT_ENCODING = getProperty(props, "stdout.encoding");
SUN_JNU_ENCODING = getProperty(props, "sun.jnu.encoding");
JAVA_PROPERTIES_DATE = getProperty(props, "java.properties.date", null);
JAVA_LOCALE_USE_OLD_ISO_CODES = getProperty(props, "java.locale.useOldISOCodes", "");
OS_NAME = getProperty(props, "os.name");
OS_ARCH = getProperty(props, "os.arch");
OS_VERSION = getProperty(props, "os.version");
Expand Down Expand Up @@ -258,13 +256,6 @@ public static String javaPropertiesDate() {
return JAVA_PROPERTIES_DATE;
}

/**
* {@return the {@code java.locale.useOldISOCodes} system property}
*/
public static String javaLocaleUseOldISOCodes() {
return JAVA_LOCALE_USE_OLD_ISO_CODES;
}

/**
* {@return the {@code os.name} system property}
*/
Expand Down
24 changes: 11 additions & 13 deletions src/java.base/share/classes/sun/util/locale/BaseLocale.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@

import jdk.internal.misc.CDS;
import jdk.internal.util.ReferencedKeySet;
import jdk.internal.util.StaticProperty;
import jdk.internal.vm.annotation.Stable;

import java.util.StringJoiner;
Expand Down Expand Up @@ -110,16 +109,14 @@ public ReferencedKeySet<BaseLocale> get() {
private @Stable int hash;

/**
* Boolean for the old ISO language code compatibility.
* The system property "java.locale.useOldISOCodes" is not security sensitive,
* so no need to ensure privileged access here.
* Emit the warning message if the system property "java.locale.useOldISOCodes" is
* specified.
*/
private static final boolean OLD_ISO_CODES = StaticProperty.javaLocaleUseOldISOCodes()
.equalsIgnoreCase("true");
static {
if (OLD_ISO_CODES) {
System.err.println("WARNING: The use of the system property \"java.locale.useOldISOCodes\"" +
" is deprecated. It will be removed in a future release of the JDK.");
if (!System.getProperty("java.locale.useOldISOCodes", "").isEmpty()) {
System.err.println("WARNING: The system property" +
" \"java.locale.useOldISOCodes\" is no longer supported." +
" Any specified value will be ignored.");
}
}

Expand Down Expand Up @@ -166,7 +163,8 @@ public static BaseLocale getInstance(String language, String script,
}
}

// JDK uses deprecated ISO639.1 language codes for he, yi and id
// Normalize deprecated ISO 639-1 language codes for Hebrew, Yiddish,
// and Indonesian to their current standard forms.
if (!language.isEmpty()) {
language = convertOldISOCodes(language);
}
Expand All @@ -183,9 +181,9 @@ public static BaseLocale getInstance(String language, String script,

public static String convertOldISOCodes(String language) {
Copy link
Member

Choose a reason for hiding this comment

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

It was there before this change, but above on line 166 I think we should update the outdated comment,

// JDK uses deprecated ISO639.1 language codes for he, yi and id

return switch (language) {
case "he", "iw" -> OLD_ISO_CODES ? "iw" : "he";
case "id", "in" -> OLD_ISO_CODES ? "in" : "id";
case "yi", "ji" -> OLD_ISO_CODES ? "ji" : "yi";
case "iw" -> "he";
case "in" -> "id";
case "ji" -> "yi";
default -> language;
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@
import java.util.regex.Pattern;
import java.util.stream.Stream;

import jdk.internal.util.StaticProperty;
import sun.util.resources.LocaleData;
import sun.util.resources.OpenListResourceBundle;
import sun.util.resources.TimeZoneNamesBundle;
Expand Down Expand Up @@ -288,16 +287,6 @@ public String getCurrencyName(String key) {
}

public String getLocaleName(String key) {
// Get names for old ISO codes with new ISO code resources
if (StaticProperty.javaLocaleUseOldISOCodes().equalsIgnoreCase("true")) {
key = switch (key) {
case "iw" -> "he";
case "in" -> "id";
case "ji" -> "yi";
default -> key;
};
}

Object localeName = null;
String cacheKey = LOCALE_NAMES + key;

Expand Down
42 changes: 13 additions & 29 deletions test/jdk/java/util/Locale/LocaleTest.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand All @@ -26,7 +26,7 @@
* 4118587 4118595 4122371 4126371 4126880 4135316 4135752 4139504 4139940 4143951
* 4147315 4147317 4147552 4335196 4778440 4940539 5010672 6475525 6544471 6627549
* 6786276 7066203 7085757 8008577 8030696 8170840 8174269 8255086 8263202 8287868
* 8337603
* 8337603 8355522
* @summary test Locales
* @modules jdk.localedata
* @run junit LocaleTest
Expand Down Expand Up @@ -709,34 +709,18 @@ public void TestChangedISO639Codes() {
Locale indonesianOld = Locale.of("in");
Locale indonesianNew = Locale.of("id");

if ("true".equalsIgnoreCase(System.getProperty("java.locale.useOldISOCodes"))) {
if (!hebrewNew.getLanguage().equals("iw")) {
fail("Got back wrong language code for new Hebrew: expected \"iw\", got \""
+ hebrewNew.getLanguage() + "\"");
}
if (!yiddishNew.getLanguage().equals("ji")) {
fail("Got back wrong language code for new Yiddish: expected \"ji\", got \""
+ yiddishNew.getLanguage() + "\"");
}
if (!indonesianNew.getLanguage().equals("in")) {
fail("Got back wrong language code for new Indonesian: expected \"in\", got \""
+ indonesianNew.getLanguage() + "\"");
}
} else {
if (!hebrewOld.getLanguage().equals("he")) {
fail("Got back wrong language code for old Hebrew: expected \"he\", got \""
+ hebrewNew.getLanguage() + "\"");
}
if (!yiddishOld.getLanguage().equals("yi")) {
fail("Got back wrong language code for old Yiddish: expected \"yi\", got \""
+ yiddishNew.getLanguage() + "\"");
}
if (!indonesianOld.getLanguage().equals("id")) {
fail("Got back wrong language code for old Indonesian: expected \"id\", got \""
+ indonesianNew.getLanguage() + "\"");
}
if (!hebrewOld.getLanguage().equals("he")) {
fail("Got back wrong language code for old Hebrew: expected \"he\", got \""
+ hebrewNew.getLanguage() + "\"");
}
if (!yiddishOld.getLanguage().equals("yi")) {
fail("Got back wrong language code for old Yiddish: expected \"yi\", got \""
+ yiddishNew.getLanguage() + "\"");
}
if (!indonesianOld.getLanguage().equals("id")) {
fail("Got back wrong language code for old Indonesian: expected \"id\", got \""
+ indonesianNew.getLanguage() + "\"");
}

}

/**
Expand Down
15 changes: 6 additions & 9 deletions test/jdk/java/util/Locale/UseOldISOCodesTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

/*
* @test
* @bug 8295232 8353118
* @bug 8295232 8353118 8355522
* @summary Tests for the "java.locale.useOldISOCodes" system property
* @library /test/lib
* @run junit UseOldISOCodesTest
Expand All @@ -34,7 +34,7 @@

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;

public class UseOldISOCodesTest {

Expand All @@ -44,20 +44,17 @@ public void testUseOldISOCodes() throws Exception {
.outputTo(System.out)
.errorTo(System.err);
oa.shouldHaveExitValue(0);
oa.stderrShouldMatch("WARNING: The use of the system property \"java.locale.useOldISOCodes\" is deprecated. It will be removed in a future release of the JDK.");
oa.stderrShouldMatch("WARNING: The system property \"java.locale.useOldISOCodes\" is no longer supported. Any specified value will be ignored.");
}

static class Runner {
private static final String obsoleteCode = "iw";
private static final String newCode = "he";

public static void main(String[] args) {
// Ensure java.locale.useOldISOCodes is only interpreted at runtime startup
// Should have no effect
System.setProperty("java.locale.useOldISOCodes", "false");
Locale locale = Locale.of(newCode);
assertEquals(obsoleteCode, locale.getLanguage(),
"newCode 'he' was not mapped to 'iw' with useOldISOCodes=true");
// Ensure java.locale.useOldISOCodes should have no effect
assertNotEquals(obsoleteCode, Locale.of(newCode).getLanguage(),
"newCode 'he' was mapped to 'iw' with useOldISOCodes=true");
}
}
}