HashMap Serialization and Deserialization Changes

We work with an in-memory data network (IMDG) and we have a migration tool. To verify that all objects have been successfully transferred, we compute a set of objects from its serialized version.

We see some problems with the HashMap where we serialize it, but when we deserialize it, the checksum changes. Here is a simple example:

@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 is as follows:

 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 a checksum calculation method:

 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 tc1 and tc2 cards, you can see that the elements are not in the same place:

 {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 a HashMap and get the same checksum when I deserialize it. Do you know if there is a solution or am I doing something wrong?

Thanks!

Diego

+4
source share
3 answers

You are not doing anything wrong, it is simply impossible to do with the HashMap. HashMap does not guarantee ordering. Use TreeMap instead.

Based on tables based on a hash table Map interface. This implementation provides the entire optional map of operations and allows null values ​​and a null key. (The HashMap class is roughly equivalent to the Hashtable, except that it is unsynchronized and allows nulls.) This class makes no guarantee regarding the order of the map; in particular, this does not guarantee that the order will remain constant over time.

Source: Hashmap

+4
source

Your checksum cannot depend on the order of the records since the HashMap is not ordered. An alternative to using TreeMap is LinkedHashMap (which saves the order), but the real solution is to use hashCode, which is independent of the order of the records.

+4
source

Use LinkedHashMap, which is order. TreeMap is not ordered. TreeMap is a sorted map. TreeMap sorts items regardless of insertion order.

0
source

All Articles