2011-05-13 101 views
4

我們正在處理內存數據網格(IMDG),並且我們有一個遷移工具。爲了驗證所有對象都已成功遷移,我們從其序列化版本計算對象的chucksum。HashMap序列化和反序列化更改

我們看到HashMap的一些問題,我們在這裏序列化它,但是當我們反序列化它時,校驗和會發生變化。下面是一個簡單的測試案例:

@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); 
} 

的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")); 
    } 
} 

這是計算校驗方法:

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(); 
} 

如果您打印的地圖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} 

我希望能夠序列化HashMap並獲得相同的校驗和時,我反序列化它。你知道是否有解決方案,或者我做錯了什麼?

謝謝!

Diego

回答

4

你沒有做錯任何事,它只是無法用HashMap完成。在HashMap中,訂單不能保證。改爲使用TreeMap

基於哈希表的實現 Map接口。此實現 提供了所有可選映射操作,並允許空值 和空密鑰。 (HashMap類 大致等同於Hashtable, ,不同之處在於它不同步並且 允許爲空。)此類不會保證地圖的順序爲 ; 特別是,它不保證 該訂單將隨時間保持不變 。

來源:Hashmap

+0

謝謝!我想避免將它改爲另一個實現,但它最終成爲更好的解決方案,因爲它還解決了從IMDG持續到關係數據庫時遇到的其他一些問題。 – dgaviola 2011-05-13 17:21:15

4

你的檢查總和不能依賴項的順序作爲HashMap中沒有訂購。使用TreeMap的替代方法是LinkedHashMap(它保留了順序),但真正的解決方案是使用不依賴於條目順序的hashCode。

+0

我也在考慮建議LinkedHashMap,但即使通過反序列化也能保證順序嗎?一定是,我想。這不是很清楚:http://download.oracle.com/javase/6/docs/api/serialized-form.html#java.util。LinkedHashMap – 2011-05-13 15:02:40

+0

@Sean,我不確定它記錄在任何地方,但我發現它是。我傾向於使用LHM作爲理所當然的事情,因爲它傾向於使調試變得更容易,但我會避免依靠其訂單進行生產。 – 2011-05-13 15:06:32

+1

校驗和取決於HashMap的序列化,顯然取決於順序。我最終將類型更改爲TreeMap,因爲它還幫助我們解決了從IMDG持續到關係數據庫時遇到的其他問題。 – dgaviola 2011-05-13 17:20:03

0

使用LinkedHashMap,它是第一個。 TreeMap未訂購。 TreeMap是有排序的地圖。 TreeMap對元素進行排序,而與插入順序無關。