hessian和xfire序列化反序列化使用注意

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();
            }
        }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值