hessian序列化的坑
2021-01-07 本文已影响0人
PataPataPa_2718
子类和父类不能有同名字段
可以参看这篇文章:
https://blog.51cto.com/tianya23/582256
学习记录,自我总结一下
hessian序列化对象的时候,默认使用的com.caucho.hessian.io.JavaSerializer
,这里只说普通对象,
JavaSerializer
的writeObject
方法会调用writeInstance
方法来序列化字段,代码如下:
@Override
public void writeInstance(Object obj, AbstractHessianOutput out)
throws IOException
{
try {
for (int i = 0; i < _fields.length; i++) {
Field field = _fields[i];
_fieldSerializers[i].serialize(out, obj, field);
}
} catch (RuntimeException e) {
throw new RuntimeException(e.getMessage() + "\n class: "
+ obj.getClass().getName()
+ " (object=" + obj + ")",
e);
} catch (IOException e) {
throw new IOExceptionWrapper(e.getMessage() + "\n class: "
+ obj.getClass().getName()
+ " (object=" + obj + ")",
e);
}
}
有循环可以看出,这里是按照字段顺序依次序列化,而_fields又是从哪儿来的呢?
我们找到JavaSerializer的构造方法:
public JavaSerializer(Class<?> cl)
{
introspect(cl);
_writeReplace = getWriteReplace(cl);
if (_writeReplace != null)
_writeReplace.setAccessible(true);
}
继续跟踪,可以看到introspect
方法,它的代码片段如下:
protected void introspect(Class<?> cl)
{
if (_writeReplace != null)
_writeReplace.setAccessible(true);
ArrayList<Field> primitiveFields = new ArrayList<Field>();
ArrayList<Field> compoundFields = new ArrayList<Field>();
//循环先获得当前类字段,然后再获得父类字段
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中
ArrayList<Field> fields = new ArrayList<Field>();
fields.addAll(primitiveFields);
fields.addAll(compoundFields);
_fields = new Field[fields.size()];
fields.toArray(_fields);
_fieldSerializers = new FieldSerializer[_fields.length];
//依次获取fieldSerializer
for (int i = 0; i < _fields.length; i++) {
_fieldSerializers[i] = getFieldSerializer(_fields[i].getType());
}
}
introspect
方法也是先获得当前class的字段,然后再获得父类的字段。所有字段放到arraylist中,因此,序列化的时候是子类数据在前,父类数据在后。
这时候,我们看看反序列化类
com.caucho.hessian.io.JavaDeserializer
,它的构造函数如下:
public JavaDeserializer(Class<?> cl, FieldDeserializer2Factory fieldFactory)
{
_type = cl;
//获取字段map
_fieldMap = getFieldMap(cl, fieldFactory);
_readResolve = getReadResolve(cl);
if (_readResolve != null) {
_readResolve.setAccessible(true);
}
_constructor = getConstructor(cl);
_constructorArgs = getConstructorArgs(_constructor);
}
里面getFieldMap
方法如下:
protected HashMap<String,FieldDeserializer2>
getFieldMap(Class<?> cl, FieldDeserializer2Factory fieldFactory)
{
HashMap<String,FieldDeserializer2> fieldMap
= new HashMap<String,FieldDeserializer2>();
//for循环先获得子类字段,然后再获得父类字段
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();
}
*/
FieldDeserializer2 deser = fieldFactory.create(field);
fieldMap.put(field.getName(), deser);
}
}
return fieldMap;
}
这里也是先获得当前类的字段,然后再获得父类的字段,但是如果子类和父类字段同名,fieldMap只会有一个字段名称key。
在反序列化字段接收值的时候,会调用readMap
:
public Object readMap(AbstractHessianInput in, Object obj)
throws IOException
{
try {
int ref = in.addRef(obj);
while (! in.isEnd()) {
Object key = in.readObject();
FieldDeserializer2 deser = _fieldMap.get(key);
if (deser != null)
deser.deserialize(in, obj);
else
in.readObject();
}
in.readMapEnd();
Object resolve = resolve(in, obj);
if (obj != resolve)
in.setRef(ref, resolve);
return resolve;
} catch (IOException e) {
throw e;
} catch (Exception e) {
throw new IOExceptionWrapper(e);
}
}