1、hessian
1)序列化
hessian序列化一个对象时,默认的序列化类是com.caucho.hessian.io.JavaSerializer。JavaSerializer的writeObject方法代码片段如下: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));
}
序列化时将属性和属性值都写入到流中,属性_fields是在JavaSerializer的构造函数里初始化的,获取当前Class的所有属性,接着获取父类的所有属性,所有属性都放在一个数组里。
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;
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);
}
2)反序列化
反序列化的时候,所有属性放在了一个HashMap里,HashMap的key不能重复。这样就有问题,如果子类和父类有同名的字段就会有问题,子类的值会被父类的值覆盖掉,父类的值不会填充。JavaDeserializer的readObject代码片段如下:从流里面拿出属性名,在_fieldMap中找属性对应的FieldDeserializer。找到后反序列化对象,未找到则从流中跳过当前属性。所以反序列化时双方属性的交集值是准确的,反序列化未找到的属性保持对应类型的默认值。
for (int i = 0; i < fieldNames.length; i++) {
String name = fieldNames[i];
FieldDeserializer deser = (FieldDeserializer) _fieldMap.get(name);
if (deser != null)
deser.deserialize(in, obj);
else
in.readObject();
}
_fieldMap初始化构造属性名到属性反序列化器的映射,先填充类自身属性,后填充父类属性。若子类和父类存在同名属性则使用子类的反序列化器
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;
try {
field.setAccessible(true);
} catch (Throwable e) {
e.printStackTrace();
}
fieldMap.put(field.getName(), field);
}
}
return fieldMap;
}
然后根据属性名读取属性值,JavaDeserializer的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 + "\n"
+ e.toString());
e1.initCause(e);
throw e1;
}
} else {
Object value = in.readObject();
}
}
序列化的时候所有属性会被按顺序写入,反序列化的时候按照序列化的顺序读取fieldName,在fieldMap中查找对应Field,找到后初始化对象并填充value。这样如果序列化和反序列化时class的属性个数和名称不一致,那反序列化时双方属性的交集值是准确的,反序列化未找到的属性保持对应类型的默认值。
另外对于同名字段,写的时候同名属性先写子类的,再写父类的。读的时候子类的该字段值会被赋值两次,总是被父类的值覆盖,而父类的值是对应类型的默认值。导致子类和父类字段值都丢失。
3)使用注意点:
1)使用hessian序列化时,一定要注意子类和父类不能有同名字段。2)使用hessian序列化时,待序列化对象必须有默认构造函数。
3)反序列化时可以在序列化流中找的属性被填充,找不到的属性用对应类型的默认值。
Xfire
序列化注意点
1)待序列化类型必须有默认构造函数。private Constructor<T> getConstructor0(Class[] parameterTypes,int which) throws NoSuchMethodException
{
Constructor[] constructors = privateGetDeclaredConstructors((which == Member.PUBLIC));
for (int i = 0; i < constructors.length; i++) {
if (arrayContentsEq(parameterTypes,constructors[i].getParameterTypes())) {
return getReflectionFactory().copyConstructor(constructors[i]);
}
}
throw new NoSuchMethodException(getName() + ".<init>" + argumentTypesToString(parameterTypes));
}
private HashMap pdStore = new HashMap();
2)属性描述器以Map格式存储,同名属性描述器以List对应Map的一个Key
/**
* Adds the property descriptor to the list store.
*/
private void addPropertyDescriptor(PropertyDescriptor pd) {
String propName = pd.getName();
List list = (List)pdStore.get(propName);
if (list == null) {
list = new ArrayList();
pdStore.put(propName, list);
}
list.add(pd);
}
//获取类型的属性描述器时将描述器Map转为列表
private PropertyDescriptor[] getTargetPropertyInfo() {
//....
result = (PropertyDescriptor[])properties.values().toArray(result);
//...
}
3)方法描述器以Map格式存储,同名方法描述器合成后对应Map中一个Key。
String name = md.getName();
MethodDescriptor old = (MethodDescriptor)methods.get(name);
if (old == null) {
// This is the common case.
methods.put(name, md);
return;
}
String[] p1 = md.getParamNames();
String[] p2 = old.getParamNames();
boolean match = false;
if (p1.length == p2.length) {
match = true;
for (int i = 0; i < p1.length; i++) {
if (p1[i] != p2[i]) {
match = false;
break;
}
}
}
if (match) {
MethodDescriptor composite = new MethodDescriptor(old, md);
methods.put(name, composite);
return;
}
4)读写属性需要getMethod,setMethod,找不到对应方法会报错
try
{
PropertyDescriptor desc = getTypeInfo().getPropertyDescriptorFromMappedName(name);
Method m = desc.getReadMethod();
if (m == null)
throw new XFireFault("No read method for property " + name + " in class "+ object.getClass().getName(), XFireFault.SENDER);
return m.invoke(object, new Object[0]);
}
读方法名初始化
if (type == boolean.class || type == null) {
readMethodName = "is" + getBaseName();
} else {
readMethodName = "get" + getBaseName();
}
// Since there can be multiple write methods but only one getter
// method, find the getter method first so that you know what the
// property type is. For booleans, there can be "is" and "get"
// methods. If an "is" method exists, this is the official
// reader method so look for this one first.
readMethod = Introspector.findMethod(cls, readMethodName, 0);
if (readMethod == null) {
readMethodName = "get" + getBaseName();
readMethod = Introspector.findMethod(cls, readMethodName, 0);
}
写入流程
BeanTypeInfo的属性描述器初始化到element,element到Type,type写入属性
PropertyDescriptor[] descriptors;
initialize()
mapProperty()
mapElement(String property, QName mappedName)
List elements = new ArrayList();
for (Iterator itr = info.getElements(); itr.hasNext();){
QName name = (QName) itr.next();
if (info.isExtension()&& info.getPropertyDescriptorFromMappedName(name).getReadMethod().getDeclaringClass() != info.getTypeClass()){
continue;
}
Object value = readProperty(object, name);
Type type = getType(info, name);
type = AegisBindingProvider.getWriteType(context, value, type);
MessageWriter cwriter;
// Write the value if it is not null.
if (value != null){
cwriter = getWriter(writer, name, type);
if (type == null)
throw new XFireRuntimeException("Couldn't find type for " + value.getClass()+ " for property " + name);
type.writeObject(value, cwriter, context);
cwriter.close();
}
读入流程
BeanTypeInfo的属性描述器初始化到attributes,attribute到Type,type读入属性
PropertyDescriptor[] descriptors;
initialize()
mapProperty()
mapAttribute(name, createMappedName(pd));
List attribute = new ArrayList();
for (Iterator itr = info.getAttributes(); itr.hasNext();){
QName name = (QName) itr.next();
Object value = readProperty(object, name);
if (value != null){
Type type = getType(info, name);
if (type == null)
throw new XFireRuntimeException("Couldn't find type for " + value.getClass()+ " for property " + name);
MessageWriter cwriter = writer.getAttributeWriter(name);
type.writeObject(value, cwriter, context);
cwriter.close();
}
}
反序列化注意点
反序列化时,根据MessageContext中的name在自己的根据自己的BeanType找不到对应Type,跳过这个属性。所以反序列化时拿到的是写入属性(序列化属性集合)和待读属性(反序列化类型属性集合)的交集。剩余属性为类型的默认值。while (reader.hasMoreElementReaders()) {
MessageReader childReader = reader.getNextElementReader();
QName name = childReader.getName();
BeanType parent = getBeanTypeWithProperty(name);
Type defaultType = null;
if (parent != null) {
info = parent.getTypeInfo();
defaultType = info.getType(name);
} else {
defaultType = null;
}
Type type = AegisBindingProvider.getReadType(childReader.getXMLStreamReader(), context,defaultType, getTypeMapping());
if (type != null) {
if (!childReader.isXsiNil()) {
Object writeObj = type.readObject(childReader, context);
if (isProxy) {
delegate.writeProperty(name.getLocalPart(), writeObj);
} else {
writeProperty(name, object, writeObj, clazz, info);
}
}
//...
} else {
childReader.readToEnd();
}
}