Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8170889

LocaleMatcher case conversion issues

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Duplicate
    • Icon: P3 P3
    • 9
    • 9
    • core-libs
    • None

      A colleague reports:

      -------
      There is another issue (arguably a bug) in sun.util.locale.LocaleMatcher and therefore the java.util.Locale APIs (for RFC 4647 Matching of Language Tags) built on top of it:

      Locale offers some APIs that lookup / filter language tags represented as Strings. Currently, the tags are converted to lowercase before they are returned, except if the query contains a "*" wildcard (matches everything) in which case they are returned verbatim.

      RFC 4647, and Locale/LanguageRange / language tag convention all mandate case insensitive comparison as part of the filtering. However, I am not aware of anything mandating a conversion to lowercase as part of the filtering. Since the API both accepts and returns language tags represented as Strings, it probably makes sense for that API to preserve case (if it accepted instances of some new class LanguageTag or similar, it would make sense for that class to implement appropriate equals() semantics); at the very least, the current behavior of LocaleMatcher.filterBasic() to preserve case for the LanguageRange("*") but not for any others is inconsistent.

      Some test cases that currently all fail but would all pass if the Locale APIs that filter and look up language tags represented as Strings preserved case (tested on OpenJDK 8 code).
      ---

      Here's a repro recipe (requires junit):

       $ (export PATH=$HOME/jdk/jdk9/bin:$PATH CLASSPATH=$HOME/jsr166/pristine/lib/junit.jar:. ; cat LocaleTest.java; javac LocaleTest.java && java org.junit.runner.JUnitCore LocaleTest)
      import junit.framework.TestCase;
      import java.util.List;
      import java.util.Locale;
      import java.util.Locale.LanguageRange;
      import static java.util.Collections.singletonList;
      import static java.util.Locale.FilteringMode.EXTENDED_FILTERING;

      public class LocaleTest extends TestCase {
          public void testTagCasePreserved_lookupTag() {
              List<LanguageRange> inputRanges = singletonList(new LanguageRange("ja-JP"));
              assertEquals("ja-JP", Locale.lookupTag(inputRanges, singletonList("ja-JP")));
          }

          public void testTagCasePreserved_filter_basic() {
              List<LanguageRange> inputRanges = singletonList(new LanguageRange("ja-JP"));
              assertEquals(singletonList("ja-JP"), Locale.filterTags(inputRanges, singletonList("ja-JP")));
          }

          public void testTagCasePreserved_filter_extended() {
              List<LanguageRange> inputRanges = singletonList(new LanguageRange("ja-JP"));
              assertEquals(singletonList("ja-JP"),
                      Locale.filterTags(inputRanges, singletonList("ja-JP"), EXTENDED_FILTERING));
          }
      }
      JUnit version 4.5
      .E.E.E
      Time: 0.006
      There were 3 failures:
      1) testTagCasePreserved_filter_basic(LocaleTest)
      junit.framework.AssertionFailedError: expected:<[ja-JP]> but was:<[ja-jp]>
      at junit.framework.Assert.fail(Assert.java:47)
      at junit.framework.Assert.failNotEquals(Assert.java:277)
      at junit.framework.Assert.assertEquals(Assert.java:64)
      at junit.framework.Assert.assertEquals(Assert.java:71)
      at LocaleTest.testTagCasePreserved_filter_basic(LocaleTest.java:16)
      at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
      at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.base/java.lang.reflect.Method.invoke(Method.java:538)
      at junit.framework.TestCase.runTest(TestCase.java:168)
      at junit.framework.TestCase.runBare(TestCase.java:134)
      at junit.framework.TestResult$1.protect(TestResult.java:110)
      at junit.framework.TestResult.runProtected(TestResult.java:128)
      at junit.framework.TestResult.run(TestResult.java:113)
      at junit.framework.TestCase.run(TestCase.java:124)
      at junit.framework.TestSuite.runTest(TestSuite.java:232)
      at junit.framework.TestSuite.run(TestSuite.java:227)
      at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:79)
      at org.junit.runners.Suite.runChild(Suite.java:115)
      at org.junit.runners.Suite.runChild(Suite.java:23)
      at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:180)
      at org.junit.runners.ParentRunner.access$000(ParentRunner.java:41)
      at org.junit.runners.ParentRunner$1.evaluate(ParentRunner.java:173)
      at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
      at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
      at org.junit.runners.ParentRunner.run(ParentRunner.java:220)
      at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
      at org.junit.runner.JUnitCore.run(JUnitCore.java:116)
      at org.junit.runner.JUnitCore.run(JUnitCore.java:107)
      at org.junit.runner.JUnitCore.runMain(JUnitCore.java:88)
      at org.junit.runner.JUnitCore.runMainAndExit(JUnitCore.java:54)
      at org.junit.runner.JUnitCore.main(JUnitCore.java:46)
      2) testTagCasePreserved_lookupTag(LocaleTest)
      junit.framework.ComparisonFailure: null expected:<ja-[JP]> but was:<ja-[jp]>
      at junit.framework.Assert.assertEquals(Assert.java:81)
      at junit.framework.Assert.assertEquals(Assert.java:87)
      at LocaleTest.testTagCasePreserved_lookupTag(LocaleTest.java:11)
      at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
      at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.base/java.lang.reflect.Method.invoke(Method.java:538)
      at junit.framework.TestCase.runTest(TestCase.java:168)
      at junit.framework.TestCase.runBare(TestCase.java:134)
      at junit.framework.TestResult$1.protect(TestResult.java:110)
      at junit.framework.TestResult.runProtected(TestResult.java:128)
      at junit.framework.TestResult.run(TestResult.java:113)
      at junit.framework.TestCase.run(TestCase.java:124)
      at junit.framework.TestSuite.runTest(TestSuite.java:232)
      at junit.framework.TestSuite.run(TestSuite.java:227)
      at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:79)
      at org.junit.runners.Suite.runChild(Suite.java:115)
      at org.junit.runners.Suite.runChild(Suite.java:23)
      at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:180)
      at org.junit.runners.ParentRunner.access$000(ParentRunner.java:41)
      at org.junit.runners.ParentRunner$1.evaluate(ParentRunner.java:173)
      at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
      at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
      at org.junit.runners.ParentRunner.run(ParentRunner.java:220)
      at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
      at org.junit.runner.JUnitCore.run(JUnitCore.java:116)
      at org.junit.runner.JUnitCore.run(JUnitCore.java:107)
      at org.junit.runner.JUnitCore.runMain(JUnitCore.java:88)
      at org.junit.runner.JUnitCore.runMainAndExit(JUnitCore.java:54)
      at org.junit.runner.JUnitCore.main(JUnitCore.java:46)
      3) testTagCasePreserved_filter_extended(LocaleTest)
      junit.framework.AssertionFailedError: expected:<[ja-JP]> but was:<[ja-jp]>
      at junit.framework.Assert.fail(Assert.java:47)
      at junit.framework.Assert.failNotEquals(Assert.java:277)
      at junit.framework.Assert.assertEquals(Assert.java:64)
      at junit.framework.Assert.assertEquals(Assert.java:71)
      at LocaleTest.testTagCasePreserved_filter_extended(LocaleTest.java:21)
      at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
      at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.base/java.lang.reflect.Method.invoke(Method.java:538)
      at junit.framework.TestCase.runTest(TestCase.java:168)
      at junit.framework.TestCase.runBare(TestCase.java:134)
      at junit.framework.TestResult$1.protect(TestResult.java:110)
      at junit.framework.TestResult.runProtected(TestResult.java:128)
      at junit.framework.TestResult.run(TestResult.java:113)
      at junit.framework.TestCase.run(TestCase.java:124)
      at junit.framework.TestSuite.runTest(TestSuite.java:232)
      at junit.framework.TestSuite.run(TestSuite.java:227)
      at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:79)
      at org.junit.runners.Suite.runChild(Suite.java:115)
      at org.junit.runners.Suite.runChild(Suite.java:23)
      at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:180)
      at org.junit.runners.ParentRunner.access$000(ParentRunner.java:41)
      at org.junit.runners.ParentRunner$1.evaluate(ParentRunner.java:173)
      at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
      at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
      at org.junit.runners.ParentRunner.run(ParentRunner.java:220)
      at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
      at org.junit.runner.JUnitCore.run(JUnitCore.java:116)
      at org.junit.runner.JUnitCore.run(JUnitCore.java:107)
      at org.junit.runner.JUnitCore.runMain(JUnitCore.java:88)
      at org.junit.runner.JUnitCore.runMainAndExit(JUnitCore.java:54)
      at org.junit.runner.JUnitCore.main(JUnitCore.java:46)

      FAILURES!!!
      Tests run: 3, Failures: 3

            nishjain Nishit Jain
            martin Martin Buchholz
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: