Hi. I just moved from RC1 to 3.0, and I have found a problem. When using a
custom strategy on byte arrays, the method equals om TCustomObjectHash is
implemented as;
@Override
protected boolean equals( Object one, Object two ) {
//noinspection unchecked
return strategy.equals( ( T ) one, ( T ) two );
}
The problem, is that one of those two objects can be REMOVED, in which case
the cast to T gives a ClassCastException. I have resolved it by overriding
that method (see below) in my own class, but I thought you shhould know.
@Override
protected boolean equals( Object one, Object two ) {
if (!(o1 instanceof byte)) return false;
if (!(o2 instanceof byte)) return false;
return strategy.equals( ( byte ) one, ( byte ) two );
}
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
-
2011-09-13
Here is a full class illustrating the problem. If you run it, it will fail
with a ClassCastException. Thanks!
private static byte random(int n, Random rnd) {
byte ba = new byte;
for (int i = 0; i < ba.length; i++) {
ba_ = (byte)rnd.nextInt();
}
return ba;
}
private static class ByteArrayStrategy implements HashingStrategy<byte> { </byte>
// Copied from Arrays.hashCode, but applied only to the first four bytes
@Override
public int computeHashCode(byte bytes) {
if (bytes == null) return 0;
int h = 1;
for (int i = 0; i < 4; i++) h = 31 * h + bytes_;
return h;
}
public static void main(String args) {
Random rnd = new Random(1234);
TCustomHashMap<byte, integer=""> map = new TCustomHashMap<byte, integer="">(new
ByteArrayStrategy());
List<byte> list = new ArrayList<byte>(); </byte></byte></byte,></byte,>
for (int i = 0; i < 1000; i++) {
byte ba = random(16, rnd);
list.add(ba);
map.put(ba, new Integer(i));
}
for (int i = 0; i < 1000; i++) {
map.remove(list.get(i));
}
// Print all nulls!
for (int i = 0; i < 1000; i++) {
System.out.println(map.get(list.get(i)));
}
}
}
__
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Patching TCustomObjectHash is probably easier than tightening the contract of
HashStrategy by requiring to handle the REMOVED corner case. FREE should not
happen, I quickly checked.
Hi. I just moved from RC1 to 3.0, and I have found a problem. When using a
custom strategy on byte arrays, the method equals om TCustomObjectHash is
implemented as;
@Override
protected boolean equals( Object one, Object two ) {
//noinspection unchecked
return strategy.equals( ( T ) one, ( T ) two );
}
The problem, is that one of those two objects can be REMOVED, in which case
the cast to T gives a ClassCastException. I have resolved it by overriding
that method (see below) in my own class, but I thought you shhould know.
@Override
protected boolean equals( Object one, Object two ) {
if (!(o1 instanceof byte)) return false;
if (!(o2 instanceof byte)) return false;
return strategy.equals( ( byte ) one, ( byte ) two );
}
Here is a full class illustrating the problem. If you run it, it will fail
with a ClassCastException. Thanks!
package com.jt.jtp;
import gnu.trove.map.hash.TCustomHashMap;
import gnu.trove.strategy.HashingStrategy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
public class TroveBug {
private static byte random(int n, Random rnd) {
byte ba = new byte;
for (int i = 0; i < ba.length; i++) {
ba_ = (byte)rnd.nextInt();
}
return ba;
}
private static class ByteArrayStrategy implements HashingStrategy<byte> { </byte>
// Copied from Arrays.hashCode, but applied only to the first four bytes
@Override
public int computeHashCode(byte bytes) {
if (bytes == null) return 0;
int h = 1;
for (int i = 0; i < 4; i++) h = 31 * h + bytes_;
return h;
}
@Override
public boolean equals(byte o1, byte o2) {
return Arrays.equals(o1, o2);
}
}
public static void main(String args) {
Random rnd = new Random(1234);
TCustomHashMap<byte, integer=""> map = new TCustomHashMap<byte, integer="">(new
ByteArrayStrategy());
List<byte> list = new ArrayList<byte>(); </byte></byte></byte,></byte,>
for (int i = 0; i < 1000; i++) {
byte ba = random(16, rnd);
list.add(ba);
map.put(ba, new Integer(i));
}
for (int i = 0; i < 1000; i++) {
map.remove(list.get(i));
}
// Print all nulls!
for (int i = 0; i < 1000; i++) {
System.out.println(map.get(list.get(i)));
}
}
}
__
Thanks, I'll take a look right away.
Rob
Patching TCustomObjectHash is probably easier than tightening the contract of
HashStrategy by requiring to handle the REMOVED corner case. FREE should not
happen, I quickly checked.
Maybe simply:
I'll try later on
Hi,
Confirming that the above proposed change fixes the reported issue. I'll
commit it to svn as well as the problem scenario (in unittest)
Johan