hessian 서열화 버그
5073 단어 hessian
try {
out.writeMapBegin(cl.getName());
for (int i = 0; i < _fields.length; i++) {
Field field = _fields[i];
out.writeString(field.getName());
out.writeObject(field.get(obj));
}
out.writeMapEnd();
} catch (IllegalAccessException e) {
throw new IOException(String.valueOf(e));
}
속성과 속성 값을 모두 흐름에 기록합니다. 여기는 아무런 문제가 없는 것 같지만, 이 Field들은 어떻게 생겼습니까?JavaSerializer의 구조 함수를 보십시오.
public JavaSerializer(Class cl) {
_writeReplace = getWriteReplace(cl);
if (_writeReplace != null) _writeReplace.setAccessible(true);
ArrayList primitiveFields = new ArrayList();
ArrayList compoundFields = new ArrayList();
for (; cl != null; cl = cl.getSuperclass()) {
Field[] fields = cl.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
if (Modifier.isTransient(field.getModifiers()) || Modifier.isStatic(field.getModifiers())) continue;
// XXX: could parameterize the handler to only deal with public
field.setAccessible(true);
if (field.getType().isPrimitive() || field.getType().getName().startsWith("java.lang.")
&& !field.getType().equals(Object.class)) primitiveFields.add(field);
else compoundFields.add(field);
}
}
ArrayList fields = new ArrayList();
fields.addAll(primitiveFields);
fields.addAll(compoundFields);
_fields = new Field[fields.size()];
fields.toArray(_fields);
}
현재class의 모든 필드를 가져오고 부모 클래스의 모든 필드를 가져옵니다.서열화할 때 모든 필드를 Array List에 놓고 이진 흐름에 순서대로 쓴다. 반서열화할 때 모든 필드는 하나의HashMap에 넣고HashMap의 키는 중복될 수 없다. 비극이 발생한다. 하위 클래스와 하위 클래스가 같은 이름이 있는 필드가 있으면 문제가 생기고 하위 클래스의 값은 하위 클래스의 값을 덮어쓴다.JavaDeserializer의 getFieldMap 방법을 보십시오. 부모 필드는 하위 필드를 덮어씁니다.
/**
* Creates a map of the classes fields.
*/
protected HashMap getFieldMap(Class cl)
{
HashMap fieldMap = new HashMap();
for (; cl != null; cl = cl.getSuperclass()) {
Field []fields = cl.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
if (Modifier.isTransient(field.getModifiers()) ||
Modifier.isStatic(field.getModifiers()))
continue;
else if (fieldMap.get(field.getName()) != null)
continue;
// XXX: could parameterize the handler to only deal with public
try {
field.setAccessible(true);
} catch (Throwable e) {
e.printStackTrace();
}
fieldMap.put(field.getName(), field);
}
}
return fieldMap;
}
그리고 필드에 따라 값을 받아서 자바 Deserializer의readMap 방법의 코드 세션을 보십시오
while (!in.isEnd()) {
Object key = in.readObject();
Field field = (Field) _fieldMap.get(key);
if (field != null) {
Object value = in.readObject(field.getType());
try {
field.set(obj, value);
} catch (Throwable e) {
IOException e1 = new IOException("Failed setting: " + field + " with " + value + "
"
+ e.toString());
e1.initCause(e);
throw e1;
}
} else {
Object value = in.readObject();
}
}
이진 데이터를 보낼 때, 하위 클래스 데이터는 앞에 있고, 부 클래스 데이터는 뒤에 있다.이진 데이터를 수신할 때, 하위 클래스 데이터는 앞에 있고, 부 클래스 데이터는 뒤에 있다.따라서 같은 이름의 필드에 대해 하위 클래스의 이 필드 값은 두 번 부여되고 항상 상위 클래스의 값에 덮어쓰여 하위 클래스의 필드 값을 잃어버린다.분석이 끝난 다음에 다시 돌아보면 ProductDraftDO에는 ActionTrace 유형 필드인 actionTrace가 있고 부류 ProductDO에도 ActionTrace 유형 필드인 actionTrace가 있다.반서열화할 때 ProductDraftDO의 actionTrace는 ProductDO의 actionTrace에 덮여 있기 때문에 ProductDraftDO의 actionTrace는 항상 비어 있습니다.왜 부류와 자류에 모두 ActionTrace가 있는지에 대해서는 역사적 원인이므로 여기서 토론하지 않는다.따라서hessian 서열화를 사용할 때 하위 클래스와 부모 클래스는 같은 이름의 필드가 있을 수 없다는 것을 반드시 주의해야 한다.dubbo를 사용할 때 정렬화 프로토콜이 지정되지 않으면 이 문제도 주의해야 합니다.