JDK-8290973 : In AffineTransform, equals(Object) is inconsistent with hashCode()
  • Type: Bug
  • Component: client-libs
  • Sub-Component: 2d
  • Affected Version: 8,11,17
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2022-07-25
  • Updated: 2022-10-10
  • Resolved: 2022-10-06
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.
JDK 20
20 masterFixed
Related Reports
Relates :  
Description
A DESCRIPTION OF THE PROBLEM :
The equals(Object) method is inconsistent with hashCode() in the AffineTransform class. This bug prevents the use of AffineTransform as keys in HashMap, unless AffineTransform construction is well-controlled or some workaround is applied before any use as key. 

More specifically, AffineTransform breaks two contracts documented in Object.equals(Object) javadoc:

* A.equals(A) returns false if at least one affine transform coefficient is NaN.
* A.equals(B) should imply A.hashCode() == B.hashCode(), but it is not the case if a coefficient is zero with an opposite sign in A and B.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Following code should print "true" but prints "false":

AffineTransform a = new AffineTransform(1, 0, 0, 1, Double.NaN, 0);
System.out.println(a.equals(a));

Following code should print either "true, true" or "false, <anything>" but print "true, false":

AffineTransform a = new AffineTransform(2, 0, 0, 3, 0, +0.0);
AffineTransform b = new AffineTransform(2, 0, 0, 3, 0, -0.0);
System.out.println(a.equals(b));
System.out.println(a.hashCode() == b.hashCode());


EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
true
true
true

or

true
false
<anything>

ACTUAL -
false
true
false


---------- BEGIN SOURCE ----------
import java.awt.geom.AffineTransform;

public class Test {
    public static void main(String[] args) {
        AffineTransform r = new AffineTransform(1, 0, 0, 1, Double.NaN, 0);
        System.out.println(r.equals(r));

        AffineTransform a = new AffineTransform(2, 0, 0, 3, 0, +0.0);
        AffineTransform b = new AffineTransform(2, 0, 0, 3, 0, -0.0);
        System.out.println(a.equals(b));
        System.out.println(a.hashCode() == b.hashCode());
    }
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Before any use of AffineTransform as a key in an HashMap:

private static double pz(double value) {
    return (value != 0) ? value : 0;
}

private static void fix(AffineTransform a) {
    a.setTransform(
        pz(a.getScaleX()),     pz(a.getShearY()),
        pz(s.getShearX()),     pz(a.getScaleY()),
        pz(a.getTranslateX()), pz(a.getTranslateY()));
}


FREQUENCY : always



Comments
Changeset: 5c030ccc Author: Martin Desruisseaux <martin.desruisseaux@geomatys.com> Committer: Jayathirth D V <jdv@openjdk.org> Date: 2022-10-06 16:03:36 +0000 URL: https://git.openjdk.org/jdk/commit/5c030cccae6cd7862b7ecc563fde4b7670f25c10
06-10-2022

A pull request was submitted for review. URL: https://git.openjdk.org/jdk/pull/9121 Date: 2022-06-10 09:39:48 +0000
25-07-2022