-
Bug
-
Resolution: Fixed
-
P4
-
1.4.2
-
b71
-
x86
-
linux
Name: gm110360 Date: 07/14/2003
FULL PRODUCT VERSION :
java version "1.4.0_01"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0_01-b03)
Java HotSpot(TM) Client VM (build 1.4.0_01-b03, mixed mode)
also:
java version "1.3.1_04"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.1_04-b02)
Java HotSpot(TM) Client VM (build 1.3.1_04-b02, mixed mode)
FULL OPERATING SYSTEM VERSION :
glibc: glibc-2.2.5-42
Kernal: Linux 2.4.18-18-7.x #1 Wed Nov 13 20:29:30 EST 2002
i686
distro: redhat-release
ADDITIONAL OPERATING SYSTEMS :
(seems like a pure java issue to me)
A DESCRIPTION OF THE PROBLEM :
Collections.reverseOrder().equals(deserialize(serialize
(Collections.reverseOrder()) returns false.
The JavaDocs for java.util.Comparator.equals suggests (but
doesn't strictly require):
"[T]his method can return true only if the specified Object
is also a comparator and it imposes the same ordering as
this comparator. Thus comp1.equals(comp2) implies that sgn
(comp1.compare(o1,o2)) == sgn(comp2.compare(o1,o2)) for
every object reference o1 and o2."
The java.util.Collections.reverseOrder method returns a
Comparator that could readily support this "soft contract",
but doesn't when serialized, deserialized and compared back
to itself.
See the sample unit test below.
Overriding Object.equals would allow
Collections.ReverseComparator to support this case as
well. Something like this:
public boolean equals(Object that) {
return (that == this ||
that instanceof Collections.ReverseComparator);
}
should suffice, since Collections.ReverseComparator is
final (although I suppose it is still possible for
instanceof to fail if "this" and "that" were loaded via
different ClassLoaders).
That Comparator suggests implementations should be
Serializable, and that ReverseComparator is itself
Serializable suggests that this problem isn't as obscure as
it might at first seem.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compare two distinct instances of
Collections.ReverseComparator and compare them using the
equals method.
One way to get two distinct instances is to serialize and
then deserialize a single instance. See sample code below.
EXPECTED VERSUS ACTUAL BEHAVIOR :
Collections.reverseOrder().equals(deserialize(serialize
(Collections.reverseOrder()) should return true.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.util.Collections;
import java.util.Comparator;
import junit.framework.*;
public class TestReverseOrder extends TestCase {
public TestReverseOrder(String name) {
super(name);
}
public static Test suite() {
return new TestSuite(TestReverseOrder.class);
}
public void testEqualsDeserializedInstance() throws Exception {
// obtain an instance of Collections.ReverseOrder
Comparator comp1 = Collections.reverseOrder();
// note that it is equal to itself
assertTrue( "equals should be reflexive", comp1.equals(comp1) );
// or assertEquals(comp1,comp1);
// serialize it
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(buffer);
out.writeObject(comp1);
// deserialize it
ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream
(buffer.toByteArray()))
Comparator comp2 = (Comparator)(in.readObject());
// note that comp1 is not equal to its deserialized clone
assertEquals( "should equal deserialized clone", comp1.equals(comp2) );
// or assertEquals(comp1,comp2);
}
}
---------- END SOURCE ----------
(Incident Review ID: 179731)
======================================================================
FULL PRODUCT VERSION :
java version "1.4.0_01"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0_01-b03)
Java HotSpot(TM) Client VM (build 1.4.0_01-b03, mixed mode)
also:
java version "1.3.1_04"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.1_04-b02)
Java HotSpot(TM) Client VM (build 1.3.1_04-b02, mixed mode)
FULL OPERATING SYSTEM VERSION :
glibc: glibc-2.2.5-42
Kernal: Linux 2.4.18-18-7.x #1 Wed Nov 13 20:29:30 EST 2002
i686
distro: redhat-release
ADDITIONAL OPERATING SYSTEMS :
(seems like a pure java issue to me)
A DESCRIPTION OF THE PROBLEM :
Collections.reverseOrder().equals(deserialize(serialize
(Collections.reverseOrder()) returns false.
The JavaDocs for java.util.Comparator.equals suggests (but
doesn't strictly require):
"[T]his method can return true only if the specified Object
is also a comparator and it imposes the same ordering as
this comparator. Thus comp1.equals(comp2) implies that sgn
(comp1.compare(o1,o2)) == sgn(comp2.compare(o1,o2)) for
every object reference o1 and o2."
The java.util.Collections.reverseOrder method returns a
Comparator that could readily support this "soft contract",
but doesn't when serialized, deserialized and compared back
to itself.
See the sample unit test below.
Overriding Object.equals would allow
Collections.ReverseComparator to support this case as
well. Something like this:
public boolean equals(Object that) {
return (that == this ||
that instanceof Collections.ReverseComparator);
}
should suffice, since Collections.ReverseComparator is
final (although I suppose it is still possible for
instanceof to fail if "this" and "that" were loaded via
different ClassLoaders).
That Comparator suggests implementations should be
Serializable, and that ReverseComparator is itself
Serializable suggests that this problem isn't as obscure as
it might at first seem.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compare two distinct instances of
Collections.ReverseComparator and compare them using the
equals method.
One way to get two distinct instances is to serialize and
then deserialize a single instance. See sample code below.
EXPECTED VERSUS ACTUAL BEHAVIOR :
Collections.reverseOrder().equals(deserialize(serialize
(Collections.reverseOrder()) should return true.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.util.Collections;
import java.util.Comparator;
import junit.framework.*;
public class TestReverseOrder extends TestCase {
public TestReverseOrder(String name) {
super(name);
}
public static Test suite() {
return new TestSuite(TestReverseOrder.class);
}
public void testEqualsDeserializedInstance() throws Exception {
// obtain an instance of Collections.ReverseOrder
Comparator comp1 = Collections.reverseOrder();
// note that it is equal to itself
assertTrue( "equals should be reflexive", comp1.equals(comp1) );
// or assertEquals(comp1,comp1);
// serialize it
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(buffer);
out.writeObject(comp1);
// deserialize it
ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream
(buffer.toByteArray()))
Comparator comp2 = (Comparator)(in.readObject());
// note that comp1 is not equal to its deserialized clone
assertEquals( "should equal deserialized clone", comp1.equals(comp2) );
// or assertEquals(comp1,comp2);
}
}
---------- END SOURCE ----------
(Incident Review ID: 179731)
======================================================================
- relates to
-
JDK-6483125 (coll) Collections.reverseOrder(Comparator) should override equals, hashCode
-
- Closed
-
-
JDK-6372554 (coll) Collections.ReverseComparator should override readResolve()
-
- Closed
-