Изменения в сериализации и десериализации HashMap - PullRequest
5 голосов
/ 13 мая 2011

Мы работаем с сеткой данных в памяти (IMDG), и у нас есть инструмент миграции. Чтобы убедиться, что все объекты успешно перенесены, мы вычисляем контрольную сумму объектов из ее сериализованной версии.

Мы видим некоторые проблемы с 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

Ответы [ 3 ]

4 голосов
/ 13 мая 2011

Ваша контрольная сумма не может зависеть от порядка записей, так как HashMap не упорядочен. Альтернативой использованию TreeMap является LinkedHashMap (который сохраняет порядок), но реальным решением является использование hashCode, который не зависит от порядка записей.

4 голосов
/ 13 мая 2011

Вы не делаете ничего плохого, это просто невозможно сделать с помощью HashMap. В HashMap порядок не гарантируется. Вместо этого используйте TreeMap.

Реализация хеш-таблицы на основе Интерфейс карты. Эта реализация предоставляет все дополнительные карты операции, и разрешает нулевые значения и нулевой ключ. (Класс HashMap примерно эквивалентно Hashtable, кроме того, что он не синхронизирован и разрешает нули.) Этот класс не делает гарантии относительно порядка карты; в частности, это не гарантирует что порядок останется постоянным со временем.

Источник: Hashmap

0 голосов
/ 03 марта 2013

Используйте LinkedHashMap, который является первым.TreeMap не заказан.TreeMap это отсортированная карта.TreeMap сортирует элементы независимо от порядка вставки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...