-
Bug
-
Resolution: Fixed
-
P4
-
8, 11, 17
-
b19
-
generic
-
generic
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
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
- relates to
-
JDK-8289389 Fix warnings: type should also implement hashCode() since it overrides Object.equals()
- Resolved
-
JDK-8226930 Recheck equals and hashCode contract for classes that override them
- Open