开发者

Complex HashMap has different hashCode after serialization

开发者 https://www.devze.com 2022-12-23 17:16 出处:网络
I am parsing a xml file into a complex HashMap looking like this: Map<String, Map<String, EcmObject>

I am parsing a xml file into a complex HashMap looking like this:

Map<String, Map<String, EcmObject>

EcmObject:

public class EcmObject implements Comparable, Serializable {
    private final EcmObjectType type;
    private final String name;
    private final List<EcmField> fields;
    private final boolean pages;

    // getter, equals, hashCode
}

EcmObjectType:

public enum EcmObjectType implements Serializable {
   FOLDER, REGISTER, DOCUMENT
}

EcmField

public class EcmField implements Comparable, Serializable {
    private final EcmFieldDataType dataType;
    private final EcmFieldControlType controlType;
    private final String name;
    private final String dbname;
    private final String internalname;
    private final Integer length;
    // getter, equals, hashCode
}

EcmFieldDataType

public enum EcmFieldDataType implements Serializable {
    TEXT, DATE, NUMBER, GROUP, DEC;
}

and EcmFieldControlType

public enum EcmFieldControl开发者_如何学JAVAType implements Serializable{
    DEFAULT, CHECKBOX, LIST, DBLIST, TEXTAREA, HIERARCHY, TREE, GRID, RADIO, PAGECONTROL, STATIC;
}

I have overwritten all hashCode and equal methods by usind commons lang's EqualsBuilder and HashCodeBuilder. Now when I copy a A HashMap this way:

Map<String, Map<String, EcmObject>> m = EcmUtil.convertXmlObjectDefsToEcmEntries(new File("e:\\objdef.xml"));
Map<String, Map<String, EcmObject>> m2;

System.out.println(m.hashCode());

ByteArrayOutputStream baos = new ByteArrayOutputStream(8 * 4096);
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(m);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);

m2 = (Map<String, Map<String, EcmObject>>) ois.readObject();

System.out.println(m.hashCode());
System.out.println(m2.hashCode());

m.hashCode() is not equal to m2.hashCode()

here is my output:

-1639352210
-2071553208
1679930154

Another strange thing is, that eg. 10 times m has the same hashcode and suddenly on the 11th time the hashcode is different...

Any ideas what this is about?


Hashcode of enum is not consistent across JVM instances. You can use hashcode of enum.toString() instead.


Since the hashCode of a HashMap is defined in terms of the hashCode of each key and value, I'd try to find out which key or element produces a different hashCode after serialization.


Ok, as Mr Sauer suggested, I wrote some test code to find out which element has a different hashCode and I found out, that all(!) EcmField-Objects have different hashCodes, but all of EcmField's parameter have got the same hashcode !!

Here are hashcode and equals implementations:

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;

    EcmField ecmField = (EcmField) o;

    return new EqualsBuilder()
            .appendSuper(super.equals(o))
            .append(controlType, ecmField.controlType)
            .append(dataType, ecmField.dataType)
            .append(dbname, ecmField.dbname)
            .append(internalname, ecmField.internalname)
            .append(length, ecmField.length)
            .append(name, ecmField.name)
            .isEquals();
}

@Override
public int hashCode() {
    return new HashCodeBuilder(13, 37)
            .append(controlType)
            .append(dataType)
            .append(dbname)
            .append(internalname)
            .append(length)
            .append(name)
            .hashCode();
}

and this is my test code

EcmField ecmFieldOne = ecmFieldsOne.get(i);
EcmField ecmFieldTwo = ecmFieldsTwo.get(i);

if (ecmFieldOne.hashCode() != ecmFieldTwo.hashCode()) {
    if (!ecmFieldOne.equals(ecmFieldsTwo)) {
        System.out.println("Field: " + ecmFieldOne.getName() + " != " + ecmFieldTwo.getName());
    }

    if (ecmFieldOne.getControlType().hashCode() != ecmFieldTwo.getControlType().hashCode()) {
        System.out.println("ControlType: " + ecmFieldOne.getControlType() + " != " + ecmFieldTwo.getControlType());
    }
    if (ecmFieldOne.getDataType().hashCode() != ecmFieldTwo.getDataType().hashCode()) {
        System.out.println("DataType: " + ecmFieldOne.getDataType() + " != " + ecmFieldTwo.getDataType());
    }
    if (ecmFieldOne.getDbname().hashCode() != ecmFieldTwo.getDbname().hashCode()) {
        System.out.println("Dbname: " + ecmFieldOne.getDbname() + " != " + ecmFieldTwo.getDbname());
    }
    if (ecmFieldOne.getInternalname().hashCode() != ecmFieldTwo.getInternalname().hashCode()) {
        System.out.println("Internalname: " + ecmFieldOne.getInternalname() + " != " + ecmFieldTwo.getInternalname());
    }
    if (ecmFieldOne.getLength().hashCode() != ecmFieldTwo.getLength().hashCode()) {
        System.out.println("Length: " + ecmFieldOne.getLength() + " != " + ecmFieldTwo.getLength());
    }
    if (ecmFieldOne.getName().hashCode() != ecmFieldTwo.getName().hashCode()) {
        System.out.println("Name: " + ecmFieldOne.getName() + " != " + ecmFieldTwo.getName());
    }
}

And only the first two if clauses are entered (if (ecmFieldOne.hashCode() != ecmFieldTwo.hashCode()) and if (!ecmFieldOne.equals(ecmFieldsTwo))), all others are false

I don't get it...

0

精彩评论

暂无评论...
验证码 换一张
取 消