简体   繁体   English

HashMap序列化和反序列化更改

[英]HashMap serialization and deserialization changes

We are working with an in memory data grid (IMDG) and we have a migration tool. 我们正在使用内存数据网格(IMDG),我们有一个迁移工具。 In order to verify that all the objects are migrated successfully, we calculate the chucksum of the objects from its serialized version. 为了验证所有对象是否已成功迁移,我们从序列化版本计算对象的chucksum。

We are seeing some problems with HashMap, where we serialize it, but when we deserialize it the checksum changes. 我们看到HashMap存在一些问题,我们将序列化它,但是当我们反序列化它时,校验和会发生变化。 Here is a simple test case: 这是一个简单的测试用例:

@Test
public void testMapSerialization() throws IOException, ClassNotFoundException {
    TestClass tc1 = new TestClass();
    tc1.init();
    String checksum1 = SpaceObjectUtils.calculateChecksum(tc1);

    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    ObjectOutput out = null;
    byte[] objBytes = null;
    out = new ObjectOutputStream(bos);
    out.writeObject(tc1);
    objBytes = bos.toByteArray();
    out.close();
    ByteArrayInputStream bis = new ByteArrayInputStream(objBytes);
    ObjectInputStream in = new ObjectInputStream(bis);
    TestClass tc2 = (TestClass) in.readObject();
    String checksum2 = SpaceObjectUtils.calculateChecksum(tc2);

    assertEquals(checksum1, checksum2);
}

The TestClass looks like this: TestClass看起来像这样:

class TestClass implements Serializable {
    private static final long serialVersionUID = 5528034467300853270L;

    private Map<String, Object> map;

    public TestClass() {
    }

    public Map<String, Object> getMap() {
        return map;
    }

    public void setMap(Map<String, Object> map) {
        this.map = map;
    }

    public void init() {
        map = new HashMap<String, Object>();
        map.put("name", Integer.valueOf(4));
        map.put("type", Integer.valueOf(4));
        map.put("emails", new BigDecimal("43.3"));
        map.put("theme", "sdfsd");
        map.put("notes", Integer.valueOf(4));
        map.put("addresses", Integer.valueOf(4));
        map.put("additionalInformation", new BigDecimal("43.3"));
        map.put("accessKey", "sdfsd");
        map.put("accountId", Integer.valueOf(4));
        map.put("password", Integer.valueOf(4));
        map.put("domain", new BigDecimal("43.3"));
    }
}

And this is the method to calculate the checksum: 这是计算校验和的方法:

public static String calculateChecksum(Serializable obj) {
    if (obj == null) {
        throw new IllegalArgumentException("The object cannot be null");
    }
    MessageDigest digest = null;
    try {
        digest = MessageDigest.getInstance("MD5");
    } catch (java.security.NoSuchAlgorithmException nsae) {
        throw new IllegalStateException("Algorithm MD5 is not present", nsae);
    }
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    ObjectOutput out = null;
    byte[] objBytes = null;
    try {
        out = new ObjectOutputStream(bos);
        out.writeObject(obj);
        objBytes = bos.toByteArray();
        out.close();
    } catch (IOException e) {
        throw new IllegalStateException(
                "There was a problem trying to get the byte stream of this object: " + obj.toString());
    }
    digest.update(objBytes);
    byte[] hash = digest.digest();
    StringBuilder hexString = new StringBuilder();
    for (int i = 0; i < hash.length; i++) {
        String hex = Integer.toHexString(0xFF & hash[i]);
        if (hex.length() == 1) {
            hexString.append('0');
        }
        hexString.append(hex);
    }
    return hexString.toString();
}

If you print the maps of tc1 and tc2, you can see that the elements are not in the same place: 如果打印tc1和tc2的地图,可以看到元素不在同一个地方:

{accessKey=sdfsd, accountId=4, theme=sdfsd, name=4, domain=43.3, additionalInformation=43.3, emails=43.3, addresses=4, notes=4, type=4, password=4}
{accessKey=sdfsd, accountId=4, name=4, theme=sdfsd, domain=43.3, emails=43.3, additionalInformation=43.3, type=4, notes=4, addresses=4, password=4}

I would like to be able to serialize the HashMap and get the same checksum when I deserialize it. 我希望能够序列化HashMap并在反序列化时获得相同的校验和。 Do you know if there is a solution or if I'm doing something wrong? 你知道是否有解决方案,或者我做错了什么?

Thanks! 谢谢!

Diego 迭戈

You are doing nothing wrong, it just can't be done with a HashMap. 你没有做错任何事,只是不能用HashMap完成。 In a HashMap, order is not guaranteed. 在HashMap中,无法保证顺序。 Use a TreeMap instead. 请改用TreeMap

Hash table based implementation of the Map interface. 基于哈希表的Map接口实现。 This implementation provides all of the optional map operations, and permits null values and the null key. 此实现提供所有可选的映射操作,并允许空值和空键。 (The HashMap class is roughly equivalent to Hashtable, except that it is unsynchronized and permits nulls.) This class makes no guarantees as to the order of the map; (HashMap类大致相当于Hashtable,除了它是不同步的并且允许空值。) 这个类不保证地图的顺序; in particular, it does not guarantee that the order will remain constant over time. 特别是,它不保证订单会随着时间的推移保持不变。

Source: Hashmap 来源: Hashmap

Your check sum cannot depend on the order of entries as HashMap is not ordered. 您的校验和不能取决于条目的顺序,因为没有订购HashMap。 An alternative to using TreeMap is LinkedHashMap (which retains an order), but the real solution is to use a hashCode which doesn't depending on the order of the entries. 使用TreeMap的另一种方法是LinkedHashMap(它保留了一个顺序),但真正的解决方案是使用一个不依赖于条目顺序的hashCode。

Use LinkedHashMap which is order one. 使用LinkedHashMap,它是第一个。 TreeMap is not ordered. TreeMap未订购。 TreeMap is sorted map. TreeMap是有序的地图。 TreeMap sorts elements irrespective of insertion order. 无论插入顺序如何,TreeMap都会对元素进行排序。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM