2011-05-13 5 views
4

IMDG (In Memory Data Grid)로 작업 중이며 마이그레이션 도구가 있습니다. 모든 객체가 성공적으로 마이그레이션되었는지 확인하기 위해 직렬화 된 버전에서 객체의 척을 계산합니다.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을 직렬화하고 동일한 체크섬을 얻고 싶습니다. 해결책이 있는지 아니면 내가 뭔가 잘못하고 있는지 아십니까?

감사합니다.

디에고는 당신이 잘못 아무것도하지 않고있다

답변

4

, 그것은 단지의 HashMap 수행 할 수 없습니다. HashMap에서는 순서가 보장되지 않습니다. 대신 TreeMap을 사용하십시오.

지도 인터페이스의 해시 테이블 기반 구현. 이 구현 은 모든 선택 맵 조작을 제공하며 null 값 과 널 (null) 키를 허용합니다. (HashMap 클래스 은 동기화되지 않고 이 null을 허용한다는 점을 제외하고는 Hashtable, 과 거의 같습니다. 이 클래스는지도의 순서에 대해 을 보장하지 않습니다. 특히, 의 주문은 일정 기간 동안 일정한 으로 유지됩니다.

출처 : HashMap에이 주문하지 않는 한Hashmap

+0

감사합니다. 다른 구현으로 변경하는 것을 피하고 싶지만 IMDG에서 관계형 데이터베이스로 지속될 때 우리가 가지고 있던 다른 문제를 해결할 때 더 나은 솔루션이되었습니다. – dgaviola

4

수표 합이 항목의 순서에 의존 할 수 없다. TreeMap을 사용하는 대안은 LinkedHashMap (주문 유지)이지만, 실제 해결책은 항목의 순서에 의존하지 않는 hashCode를 사용하는 것입니다.

+0

또한 LinkedHashMap을 제안하려고 생각했지만 Deserialization을 통해서도 보장되는 순서입니까? 그럴거야. 이것은 분명하지 않습니다. http://download.oracle.com/javase/6/docs/api/serialized-form.html#java.util.LinkedHashMap –

+0

@Sean, 어디에도 문서화되어 있지는 않지만 필자는 그것을 발견했다. LHM은 디버깅을 쉽게하기 때문에 LHM을 사용하는 경향이 있지만 프로덕션 목적을 위해 주문에 의존하는 것을 피합니다. –

+1

체크섬은 HashMap의 직렬화에 따라 다르며 순서에 따라 다릅니다. IMDG에서 관계형 데이터베이스로 지속될 때 다른 문제를 해결하는 데 도움이 되었기 때문에 유형을 TreeMap으로 변경했습니다. – dgaviola

0

주문한 LinkedHashMap을 사용하십시오. TreeMap이 주문되지 않았습니다. TreeMap은 정렬 된지도입니다. TreeMap은 삽입 순서와 관계없이 요소를 정렬합니다.

관련 문제