필드가 직렬화 된 순서와 관련된 Apache Ignite Serialization/Deserialization에 문제가 있습니다. 난은 Ignite 캐시에 다음과 같이 "B"의 인스턴스를 둘 필요가 :Apache Ignite : 역 직렬화 후 Hashmap에서 객체를 찾을 수 없습니다.
public class A {
private final String name;
public A(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public class B extends A {
private Map<B, String> mapOfB;
public B(String name) {
super(name);
mapOfB = new HashMap<>();
}
public void addB(B newB, String someString) {
mapOfB.put(newB, someString);
}
public Map<B, String> getMap() {
return mapOfB;
}
@Override
public boolean equals(Object obj) {
if(obj != null && obj instanceof B) {
if(this.getName() == null && ((B) obj).getName() == null && this == obj) {
return true;
} else if(this.getName().equals(((B) obj).getName())) {
return true;
}
}
return false;
}
@Override
public int hashCode() {
return this.getName()==null? System.identityHashCode(this):this.getName().hashCode();
}
}
의 I는 다음 코드를 실행하는 경우 :
public static void main(String[] args) {
// write your code here
B b1 = new B("first");
b1.addB(b1, "some first string");
B b2 = new B("second");
b1.addB(b2, "some second string");
// init Ignite configuration
// force java.util.Hashtable to be binary serialized,
// it prevents infinite recursion and other problems
// occurring with the Optimized Serializer
IgniteConfiguration cfg = new IgniteConfiguration();
BinaryConfiguration binConf = new BinaryConfiguration();
Collection<String> binClassNames = new LinkedList<>();
binClassNames.add("java.util.Hashtable");
binConf.setClassNames(binClassNames);
cfg.setBinaryConfiguration(binConf);
Ignition.start(cfg);
// put b1 in cache
IgniteCache cache = Ignition.ignite().getOrCreateCache("MyCache");
cache.put(b1.hashCode(), b1);
//get b1 from cache
B b1FromCache= (B) cache.get(b1.hashCode());
// print map values
System.out.println("b1 map value: " + b1.getMap().get(b1));
System.out.println("b1 from cache map value: " + b1FromCache.getMap().get(b1));
}
출력
B1지도 값은 다음과 같습니다 일부 첫 번째 문자열 캐시 맵 값에서
B1 : 널 (null)
문제는 자식의 필드가 부모의 필드보다 먼저 직렬화되기 때문에 Ignite가 B를 deserialize 할 때 먼저 빈 B 객체 (null "name"및 "mapOfB")를 생성 한 다음 mapOfB를 deserialize하려고 시도한다는 것입니다. . 그것은 Hashtable을 생성하고 그것을 포함하기 위해 포함하고있는 각 객체를 deserialize합니다.
위의 예제에서 b2의 경우 b2에 대한 참조가 아직 존재하지 않으므로 아무런 문제가 없습니다. 따라서 새로운 b2 객체가 생성되고 b2 필드가 채워집니다 ("name"필드 포함). 올바른 해시를 사용하여 해시 맵에 추가되었습니다.
그러나 b1의 경우 deserialization이 시작되었으므로 개체가 Ignit의 deserialize 된 개체 맵에 이미 있지만 null 이름 (deserialization은 b1에서 진행 중임)과이 null 이름으로 계산 된 hashCode를 사용합니다. Hashtable은 그 시점에서 계산 된 hashCode와 함께 b1을 넣습니다. 따라서 마지막에지도에서 null이 아닌 이름을 가진 b1을 찾으려고하면 찾을 수 없습니다.
A 및 B 클래스와이 오브젝트의 작성 방법 (Hashmap 작성 방법 ...)을 변경할 수 없으므로 직렬화를 변경하여 해결해야합니다. 그렇게 할 수있는 간단한 방법이 있습니까?
비고 : 실제 코드는 실제 B와 Hashmap 사이의 클래스와 함께보다 복잡합니다.
'b1.addB (새 B ("첫 번째"), "일부 첫 번째 문자열")'과 비슷한 것이지만 이것은 매우 불안정하며 'hasCode'와'equals '의 구현 방법으로 만 작동합니다. ..'B'는 불변이 아니므로 맵의 키로 사용해서는 안됩니다. –
감사. 나는 추한 것을 동의하지만이 코드를 변경할 수는 없습니다. 또한 솔루션이 작동하지만 hashMap이 어떻게 채워지는지 제어 할 수 없기 때문에 솔루션을 사용할 수 없다는 데 동의합니다. 이 텍스트를 편집하여 다시 추가하겠습니다. 다시 한 번 감사드립니다. – Nicolas