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

java.util.Locale.LanguageRange#equals is inconsistent after calling hashCode

    XMLWordPrintable

Details

    • b17
    • generic
    • generic
    • Verified

    Description

      ADDITIONAL SYSTEM INFORMATION :
      Mac OS Mojave (10.14.6)
      OpenJDK 16-EA, Oracle JDK 15, AdoptOpenJDK15, AdoptOpenJDK 14, AdoptOpenJDK 11, AdoptOpenJDK 8

      A DESCRIPTION OF THE PROBLEM :
      LanguageRange attempts to cache its hashCode value by computing it only when necessary. However, the equals implementation it employs does not reflect this fact, which causes unexpected behaviour.

      The relevant section of the equals method compares:
      hash == other.hash && range.equals(other.range) && weight == other.weight
      but the hash value of LanguageRange is always zero until hashCode() is called. The hashCode() method is essentially:
      if (hash == 0) {
        // compute and assign hash
      }
      return hash;

      It looks like this bug has existed since the introduction of LanguageRange in JDK 8.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      1. Create 2 instances of LanguageRange from the same range and weight.
      2. Observe range1.equals(range2) is true
      3. Call range1.hashCode()
      4. Observe range1.equals(range2) is now false
      5. Call range2.hashCode()
      6. Observe range1.equals(range2) is true once again

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      The LanguageRange instances should be considered equal per the equals method, as they are constructed from the same range and weight. LanguageRange is immutable.
      ACTUAL -
      The LanguageRange instances are equal if their hashCode value has not been computed. If the hashCode value of one instance is computed, the instances are not equal. If both hashCodes are computed, they are equal again.

      ---------- BEGIN SOURCE ----------
      package languagerange.equals;

      import java.util.Locale.LanguageRange;

      public class LanguageRangeMain {

      public static void main(String[] args) {
      LanguageRange range1 = new LanguageRange("en-GB", 0);
      LanguageRange range2 = new LanguageRange("en-GB", 0);

      System.out.println(range1.equals(range2)); // true

      range1.hashCode();
      System.out.println(range1.equals(range2)); // false

      range2.hashCode();
      System.out.println(range1.equals(range2)); // true
      }

      }
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      Calling the hashCode method on newly constructed LanguageRange instances is a workaround. This must be done for every LanguageRange instance used in the program.

      FREQUENCY : always


      Attachments

        Issue Links

          Activity

            People

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

              Dates

                Created:
                Updated:
                Resolved: