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