JDK-6962773 : hashCode() implementation for java.awt.SystemColor / java.awt.Color is flawed
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 7
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • OS: generic
  • CPU: generic
  • Submitted: 2010-06-21
  • Updated: 2021-07-13
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
tbdUnresolved
Related Reports
Relates :  
Relates :  
Description
SYNOPSIS
--------
hashCode() implementation for java.awt.SystemColor / java.awt.Color is flawed

OPERATING SYSTEM
----------------
All

FULL JDK VERSION
----------------
All Java 6 releases are affected by the Java 6 issue
All Java 7 builds are affected by the Java 7 issue

PROBLEM DESCRIPTION from LICENSEE
---------------------------------
The results of calling hashCode() on the static SystemColor instances defined in the SystemColor class break the hashCode() contract on Java 6, and Java 7, for different reasons on each release.

In the API documentation for java.lang.Object, the general contract for hashCode() states:

* Whenever it is invoked on the same object more than once during an
  execution of a Java application, the hashCode method must consistently
  return the same integer, provided no information used in equals
  comparisons on the object is modified. This integer need not remain
  consistent from one execution of an application to another execution
  of the same application.

* If two objects are equal according to the equals(Object) method, then
  calling the hashCode method on each of the two objects must produce
  the same integer result.

On Java 6, SystemColor.hashCode() breaks the second part of the contract. Two SystemColor instances can be equal even though their hash codes are different.

That problem is fixed on Java 7, where the integer returned by SystemColor.hashCode() is identical to the integer returned by SystemColor.getRGB(). Both calls actually invoke the methods in the parent Color class, unlike Java 6 where hashCode() is overridden in the SystemColor class. However, this causes another problem. Consider the following statement in the SystemColor API documentation:

   For systems which support the dynamic update of the system colors
   (when the user changes the colors) the actual RGB values of these
   symbolic colors will also change dynamically.

Since hashCode() is returning the RGB colour value, and that RGB colour value can change dynamically, it follows that the return value of hashCode() can also change during the execution of a Java application, thus violating part 1 of the hashCode() contract. This is proved by the second testcase provided below.

REPRODUCTION INSTRUCTIONS - JAVA 6 ISSUE
----------------------------------------
1. Compile and run SystemColorTest1.java (attached)
2. Observe the following behaviour on Java 6:

   Found equals() / hashCode() contract violation:
   Compared java.awt.SystemColor[i=14] to java.awt.SystemColor[i=1]
   java.awt.SystemColor[i=14] hashcode = 14
   java.awt.SystemColor[i=1] hashcode = 1
   java.awt.SystemColor[i=14] RGB value = -13410648
   java.awt.SystemColor[i=1] RGB value = -13410648

   Test failed!

3. Observe the following result on Java 7, which represents the expected
   behaviour:

   Test passed!

REPRODUCTION INSTRUCTIONS - JAVA 7 ISSUE
----------------------------------------
1. Compile and run SystemColorTest2.java (attached)

2. While the testcase is running, change the colour of the OS desktop
   (for example, on Windows, simply right click the desktop and change
   the setting in Properties->Desktop->Color)

3. Observe a result similar to the following with Java 7 (the integers
   involved depend on the colours you change to/from):

   hashCode() return value changed from -16777216 to -65536
   Test Failed!

4. Observer the following result with Java 6 (the expected behaviour):

   Test Passed!


TESTCASE SOURCE (ATTACHED)
------------------------------
SystemColorTest1 - JDK 6 Issue.
SystemColorTest2 - JDK 7 Issue.

Comments
- this is an issue reported against 7(7u), - there are now affected version 9 filed for this issue - 7u issues are transferred to Sustaining Nevertheless if someone have a report against 9 - please reopen and add affectedVersion 9 or 7u specific escalations might be reopen to Sustaining
10-08-2014

- this is an issue reported against 7(7u), - there are now affected version 9 filed for this issue - 7u issues are transferred to Sustaining Nevertheless if someone have a report against 9 - please reopen and add affectedVersion 9 or 7u specific escalations might be reopen to Sustaining
10-08-2014

EVALUATION The SystemColor class changes it's internal value (index) based on desktop settings. We use Color.index field as hashCode both in the Color class and the SystemColor. Once the schema changes, the index changes also. That makes the hashCode() to return new value (index). I don't see how to fix this and keep entire mechanism as well as existing application (which is an issue of further analysis) up and running. That need to be changed.
17-08-2010