KeySet 序列化异常问题整理

阿凡达2018-07-20 12:44
  今天发现诡异问题,存入缓存的是Set但是从缓存中获取的是一个ArrayList;为什么会存在这个问题呢?通过跟踪发现在Hession2序列化后变为了ArrayList,具体原因可以通过 CollectionSerializer源码分析得出,只要不是ArrayList且没有实现序列化接口的集合类都会被序列化为ArrayList ;虽然Hession支持对不实现序列化接口对象进行序列化但是序列化后对象可能不是你想要的对象。


public void writeObject(Object obj, AbstractHessianOutput out) throws IOException {
        if (!out.addRef(obj)) {
            Collection list = (Collection)obj;
            Class cl = obj.getClass();
            boolean hasEnd;
            //如果cl不是ArrayList 但是实现了 Serializable接口
            if (!cl.equals(ArrayList.class) && Serializable.class.isAssignableFrom(cl)) {
                if (!this._sendJavaType) {
                    for(hasEnd = false; cl != null; cl = cl.getSuperclass()) {
                        if (cl.getName().startsWith("java.")) {
                            hasEnd = out.writeListBegin(list.size(), cl.getName());
                            break;
                        }
                    }

                    if (cl == null) {
                        hasEnd = out.writeListBegin(list.size(), (String)null);
                    }
                } else {
                //如果sendType=true走该方法,默认sendType为true
                    hasEnd = out.writeListBegin(list.size(), obj.getClass().getName());
                }
            } else {
            //如果是ArrayList 或者不是ArrayList且没有实现Serializable接口则使用该序列化方法,将其序列化为ArrayList
                hasEnd = out.writeListBegin(list.size(), (String)null);
            }

            Iterator iter = list.iterator();

            while(iter.hasNext()) {
                Object value = iter.next();
                out.writeObject(value);
            }

            if (hasEnd) {
                out.writeListEnd();
            }

        }
    }
通过上图以及Hession序列化源码可以知道,KeySet没有实现序列化接口;此时序列化的结果是ArrayList
如何避免该问题
需要序列化对象必须实现序列化接口

本文来自网易实践者社区,经作者张伟授权发布。