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

Locale.filterTags methods ignore actual weight when matching "*" (as if it is 1)

    XMLWordPrintable

Details

    • b04
    • generic
    • generic

    Description

      A DESCRIPTION OF THE PROBLEM :
      Locale.filterTags methods ignore actual weight when matching "*" (as if it is 1) because LocaleMatcher.{filterBasic,filterExtended} do so.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Run the attached tests.


      ---------- BEGIN SOURCE ----------
      import java.util.List;
      import java.util.Locale;

      class LocaleFilterTagsTest {

        public static void main(String[] args) {
          assertFilterTags("fr-FR, fr-BG;q=0.8, *;q=0.5, en;q=0",
              List.of("en-US", "fr-FR", "fr-CA", "fr-BG"), List.of("fr-FR", "fr-BG", "fr-CA"));

          assertFilterTags("fr-FR, fr-*-BG;q=0.8, *;q=0.5, en;q=0",
              List.of("en-US", "fr-FR", "fr-CA", "fr-BG"), List.of("fr-FR", "fr-BG", "fr-CA"));

          assertFilterTags("en;q=0.2, *;q=0.6, ja",
              List.of("de-DE", "en", "ja-JP-hepburn", "fr-JP", "he"),
              List.of("ja-JP-hepburn", "de-DE", "en", "fr-JP", "he"));
        }

        private static void assertFilterTags(String ranges, List<String> tags,
            List<String> expectedTags) {
          final List<String> actualTags = Locale.filterTags(Locale.LanguageRange.parse(ranges), tags);

          if (!expectedTags.equals(actualTags)) {
            throw new AssertionError(
                String.format("Expected: %s, Actual: %s.", expectedTags, actualTags));
          }
        }
      }
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :

      Locale.filterTags methods ignore actual weight when matching "*" (as if
      it is 1) because LocaleMatcher.{filterBasic,filterExtended} do so.

      Fix the bug and add regression test cases for it as well as existing
      behavior.
      ---
       .../sun/util/locale/LocaleMatcher.java | 78 +++++--------------
       test/jdk/java/util/Locale/Bug7069824.java | 51 +++++++++++-
       2 files changed, 67 insertions(+), 62 deletions(-)

      diff --git a/src/java.base/share/classes/sun/util/locale/LocaleMatcher.java b/src/java.base/share/classes/sun/util/locale/LocaleMatcher.java
      index 93629220de5..249aee9a705 100644
      --- a/src/java.base/share/classes/sun/util/locale/LocaleMatcher.java
      +++ b/src/java.base/share/classes/sun/util/locale/LocaleMatcher.java
      @@ -124,8 +124,16 @@ public final class LocaleMatcher {
               for (LanguageRange lr : nonZeroRanges) {
                   String range = lr.getRange();
                   if (range.equals("*")) {
      - tags = removeTagsMatchingBasicZeroRange(zeroRanges, tags);
      - return new ArrayList<String>(tags);
      + for (String tag : tags) {
      + String lowerCaseTag = tag.toLowerCase(Locale.ROOT);
      +
      + if (!caseInsensitiveMatch(list, lowerCaseTag)
      + && !shouldIgnoreFilterBasicMatch(zeroRanges, lowerCaseTag)) {
      + list.add(tag);
      + }
      + }
      +
      + break;
                   } else {
                       for (String tag : tags) {
                           // change to lowercase for case-insensitive matching
      @@ -148,33 +156,6 @@ public final class LocaleMatcher {
               return list;
           }
       
      - /**
      - * Removes the tag(s) which are falling in the basic exclusion range(s) i.e
      - * range(s) with q=0 and returns the updated collection. If the basic
      - * language ranges contains '*' as one of its non zero range then instead of
      - * returning all the tags, remove those which are matching the range with
      - * quality weight q=0.
      - */
      - private static Collection<String> removeTagsMatchingBasicZeroRange(
      - List<LanguageRange> zeroRange, Collection<String> tags) {
      - if (zeroRange.isEmpty()) {
      - tags = removeDuplicates(tags);
      - return tags;
      - }
      -
      - List<String> matchingTags = new ArrayList<>();
      - for (String tag : tags) {
      - // change to lowercase for case-insensitive matching
      - String lowerCaseTag = tag.toLowerCase(Locale.ROOT);
      - if (!shouldIgnoreFilterBasicMatch(zeroRange, lowerCaseTag)
      - && !caseInsensitiveMatch(matchingTags, lowerCaseTag)) {
      - matchingTags.add(tag); // preserving the case of the input tag
      - }
      - }
      -
      - return matchingTags;
      - }
      -
           /**
            * Remove duplicate tags from the given {@code tags} by
            * ignoring case considerations.
      @@ -240,8 +221,16 @@ public final class LocaleMatcher {
               for (LanguageRange lr : nonZeroRanges) {
                   String range = lr.getRange();
                   if (range.equals("*")) {
      - tags = removeTagsMatchingExtendedZeroRange(zeroRanges, tags);
      - return new ArrayList<String>(tags);
      + for (String tag : tags) {
      + String lowerCaseTag = tag.toLowerCase(Locale.ROOT);
      +
      + if (!caseInsensitiveMatch(list, lowerCaseTag)
      + && !shouldIgnoreFilterExtendedMatch(zeroRanges, lowerCaseTag)) {
      + list.add(tag);
      + }
      + }
      +
      + break;
                   }
                   String[] rangeSubtags = range.split("-");
                   for (String tag : tags) {
      @@ -267,33 +256,6 @@ public final class LocaleMatcher {
               return list;
           }
       
      - /**
      - * Removes the tag(s) which are falling in the extended exclusion range(s)
      - * i.e range(s) with q=0 and returns the updated collection. If the extended
      - * language ranges contains '*' as one of its non zero range then instead of
      - * returning all the tags, remove those which are matching the range with
      - * quality weight q=0.
      - */
      - private static Collection<String> removeTagsMatchingExtendedZeroRange(
      - List<LanguageRange> zeroRange, Collection<String> tags) {
      - if (zeroRange.isEmpty()) {
      - tags = removeDuplicates(tags);
      - return tags;
      - }
      -
      - List<String> matchingTags = new ArrayList<>();
      - for (String tag : tags) {
      - // change to lowercase for case-insensitive matching
      - String lowerCaseTag = tag.toLowerCase(Locale.ROOT);
      - if (!shouldIgnoreFilterExtendedMatch(zeroRange, lowerCaseTag)
      - && !caseInsensitiveMatch(matchingTags, lowerCaseTag)) {
      - matchingTags.add(tag); // preserve the case of the input tag
      - }
      - }
      -
      - return matchingTags;
      - }
      -
           /**
            * The tag which is falling in the extended exclusion range(s) should
            * not be considered as the matching tag. Ignores the tag matching with the
      diff --git a/test/jdk/java/util/Locale/Bug7069824.java b/test/jdk/java/util/Locale/Bug7069824.java
      index 0eb1f21c275..dce97ef1246 100644
      --- a/test/jdk/java/util/Locale/Bug7069824.java
      +++ b/test/jdk/java/util/Locale/Bug7069824.java
      @@ -208,27 +208,61 @@ public class Bug7069824 {
           Object[][] LFilterTagsData() {
               return new Object[][] {
                       // Range, LanguageTags, FilteringMode, Expected language tags
      + {"fr-FR, fr-BG;q=0.8, *;q=0.5, en;q=0", "en-US, fr-FR, fr-CA, fr-BG",
      + null, "fr-FR, fr-BG, fr-CA"},
      + {"fr-FR, fr-*-BG;q=0.8, *;q=0.5, en;q=0", "en-US, fr-FR, fr-CA, fr-BG",
      + null, "fr-FR, fr-BG, fr-CA"},
      +
                       {"en;q=0.2, *;q=0.6, ja", "de-DE, en, ja-JP-hepburn, fr-JP, he",
      - null, "de-DE, en, ja-JP-hepburn, fr-JP, he"},
      + null, "ja-JP-hepburn, de-DE, en, fr-JP, he"},
                       {"en;q=0.2, ja-JP, fr-JP", "de-DE, en, ja-JP-hepburn, fr, he",
                               null, "ja-JP-hepburn, en"},
                       {"en;q=0.2, ja-JP, fr-JP, iw", "de-DE, he, en, ja-JP-hepburn, fr, he-IL",
                               null, "ja-JP-hepburn, he, he-IL, en"},
                       {"en;q=0.2, ja-JP, fr-JP, he", "de-DE, en, ja-JP-hepburn, fr, iw-IL",
                               null, "ja-JP-hepburn, iw-IL, en"},
      +
                       {"de-DE", "de-DE, de-de, de-Latn-DE, de-Latf-DE, de-DE-x-goethe, "
                               + "de-Latn-DE-1996, de-Deva-DE, de, de-x-DE, de-Deva",
      - MAP_EXTENDED_RANGES, "de-DE, de-DE-x-goethe"},
      + null, "de-DE, de-DE-x-goethe"},
      + {"de-*-DE", "de-DE, de-de, de-Latn-DE, de-Latf-DE, de-DE-x-goethe, "
      + + "de-Latn-DE-1996, de-Deva-DE, de, de-x-DE, de-Deva",
      + null,
      + "de-DE, de-Latn-DE, de-Latf-DE, de-DE-x-goethe, "
      + + "de-Latn-DE-1996, de-Deva-DE"},
      +
                       {"de-DE", "de-DE, de-de, de-Latn-DE, de-Latf-DE, de-DE-x-goethe, "
                               + "de-Latn-DE-1996, de-Deva-DE, de, de-x-DE, de-Deva",
                               EXTENDED_FILTERING,
                               "de-DE, de-Latn-DE, de-Latf-DE, de-DE-x-goethe, "
      - + "de-Latn-DE-1996, de-Deva-DE"},
      + + "de-Latn-DE-1996, de-Deva-DE"},
                       {"de-*-DE", "de-DE, de-de, de-Latn-DE, de-Latf-DE, de-DE-x-goethe, "
                               + "de-Latn-DE-1996, de-Deva-DE, de, de-x-DE, de-Deva",
                               EXTENDED_FILTERING,
                               "de-DE, de-Latn-DE, de-Latf-DE, de-DE-x-goethe, "
      - + "de-Latn-DE-1996, de-Deva-DE"},
      + + "de-Latn-DE-1996, de-Deva-DE"},
      +
      + {"de-DE", "de-DE, de-de, de-Latn-DE, de-Latf-DE, de-DE-x-goethe, "
      + + "de-Latn-DE-1996, de-Deva-DE, de, de-x-DE, de-Deva",
      + IGNORE_EXTENDED_RANGES,
      + "de-DE, de-DE-x-goethe"},
      + {"de-*-DE", "de-DE, de-de, de-Latn-DE, de-Latf-DE, de-DE-x-goethe, "
      + + "de-Latn-DE-1996, de-Deva-DE, de, de-x-DE, de-Deva",
      + IGNORE_EXTENDED_RANGES,
      + ""},
      +
      + {"de-DE", "de-DE, de-de, de-Latn-DE, de-Latf-DE, de-DE-x-goethe, "
      + + "de-Latn-DE-1996, de-Deva-DE, de, de-x-DE, de-Deva",
      + MAP_EXTENDED_RANGES, "de-DE, de-DE-x-goethe"},
      + {"de-*-DE", "de-DE, de-de, de-Latn-DE, de-Latf-DE, de-DE-x-goethe, "
      + + "de-Latn-DE-1996, de-Deva-DE, de, de-x-DE, de-Deva",
      + MAP_EXTENDED_RANGES, "de-DE, de-DE-x-goethe"},
      +
      + {"de-DE", "de-DE, de-de, de-Latn-DE, de-Latf-DE, de-DE-x-goethe, "
      + + "de-Latn-DE-1996, de-Deva-DE, de, de-x-DE, de-Deva",
      + REJECT_EXTENDED_RANGES, "de-DE, de-DE-x-goethe"},
      +
      + // The next test in this chain is in testLFilterTagsIAE.
               };
           }
       
      @@ -380,6 +414,15 @@ public class Bug7069824 {
                               ranges, tags, expectedTags, actualTags));
           }
       
      + @Test(expectedExceptions = IllegalArgumentException.class)
      + public void testLFilterTagsIAE() {
      + String ranges = "de-*-DE";
      + String tags = "de-DE, de-de, de-Latn-DE, de-Latf-DE, de-DE-x-goethe, "
      + + "de-Latn-DE-1996, de-Deva-DE, de, de-x-DE, de-Deva";
      + List<LanguageRange> priorityList = LanguageRange.parse(ranges);
      + showLanguageTags(Locale.filterTags(priorityList, generateLanguageTags(tags), REJECT_EXTENDED_RANGES));
      + }
      +
           @Test(dataProvider = "LLookupData")
           public void testLLookup(String ranges, String tags, String expectedLocale) {
               List<LanguageRange> priorityList = LanguageRange.parse(ranges);
      --
      2.25.1



      FREQUENCY : always


      Attachments

        Issue Links

          Activity

            People

              naoto Naoto Sato
              webbuggrp Webbug Group
              Votes:
              0 Vote for this issue
              Watchers:
              5 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: