关于数据序列化(4)自定义序列化的实现,支持常用集合框架

8 篇文章 0 订阅
4 篇文章 0 订阅

下面的示例很好的揭示了如何实现自定义序列化的方法。
支持byte, byte[], boolean, boolean[], int, int[], long, long[] ,double ,double[], String, String[], 以及Enum, List,Map两种包装类型,以及实现了ISerilizable的实体类。
稍加改造就可以在项目中应用

/**
 * 分布式序列化接口
 * 除了基本类型 其余数据需要分布式传输必须实现本接口
 * 注:实现本接口的类必须有无参构造函数!
 * @see SerializeTool#write(Object, java.io.DataOutputStream)
 * @see SerializeTool#read(java.io.DataInputStream)
 */
public interface ISerilizable {
    public void writeTo(OutputStream out) throws IOException;
    public void readFrom(InputStream in) throws IOException;
}
/**
 * 支持实现{@link ISerilizable}的类,<br>
 * 以及<b>byte,float,double,long</b>四种基本类型,<br>和
 * <b>Collection(list和set),map</b>三种集合框架,<br>和
 * <b>protobuf</b>.
 * <br>
 * TODO:循环因引用
 * @author BAO
 * @see #readFile(String fileName) 创建关闭FileInputStream DataInputStream
 * @see #read(DataInputStream in)
 * @see #readObject(DataInputStream stream) throws Exception
 * 
 */
public class SerializeTool {

    /**
     * 从流中读取数据
     * 只能顺序读 会自动进行类型转换
     * @return
     */
    public static <T> T read(DataInputStream stream) {
        try {
            return readObject(stream);
        } catch (Exception e) {
            LogCore.BASE.error("read err!", e);
            throw new SysException(e);
        }
    }

    /**
     * 从流中读取数据
     * 只能顺序读 会自动进行类型转换
     * @return
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    private static <T> T readObject(DataInputStream stream) throws Exception {
        Object result = null;

        //类型码
        int wireFormat = stream.readInt();
        //类型
        int wireType = (wireFormat & ~ARRAY);
        //是数组类型
        boolean isArray = (wireFormat & ARRAY) == ARRAY;
        //数组类型的长度
        int arrayLen = 0;
        if(isArray) {
            arrayLen = stream.readInt();
        }

        //空对象
        if(wireType == NULL) {
            return null;
        }

        //BYTE
        if(wireType == BYTE) {
            if(isArray) {
                //result = stream.readRawBytes(arrayLen);//TODO 这个方法要调研一下! API应该提供此方法
                byte[] values = new byte[arrayLen];
                for(int i = 0; i < arrayLen; i++) {
                    values[i] = stream.readByte();
                }
                result = values;
            } else {
                result = stream.readByte();
            }
        //BOOLEAN
        } else if(wireType == BOOLEAN) {
            if(isArray) {
                boolean[] values = new boolean[arrayLen];
                for(int i = 0; i < arrayLen; i++) {
                    values[i] = stream.readBoolean();
                }
                result = values;
            } else {
                result = stream.readBoolean();
            }
        //INT
        } else if(wireType == INT) {
            if(isArray) {
                int[] values = new int[arrayLen];
                for(int i = 0; i < arrayLen; i++) {
                    values[i] = stream.readInt();
                }
                result = values;
            } else {
                result = stream.readInt();
            }
        //LONG
        } else if(wireType == LONG) {
            if(isArray) {
                long[] values = new long[arrayLen];
                for(int i = 0; i < arrayLen; i++) {
                    values[i] = stream.readLong();
                }
                result = values;
            } else {
                result = stream.readLong();
            }
        //FLOAT
        } else if(wireType == FLOAT) {
            if(isArray) {
                float[] values = new float[arrayLen];
                for(int i = 0; i < arrayLen; i++) {
                    values[i] = stream.readFloat();
                }
                result = values;
            } else {
                result = stream.readFloat();
            }
        //DOUBLE
        } else if(wireType == DOUBLE) {
            if(isArray) {
                double[] values = new double[arrayLen];
                for(int i = 0; i < arrayLen; i++) {
                    values[i] = stream.readDouble();
                }
                result = values;
            } else {
                result = stream.readDouble();
            }
        //STRING
        } else if(wireType == STRING) {
            if(isArray) {
                String[] values = new String[arrayLen];
                for(int i = 0; i < arrayLen; i++) {
                    values[i] = stream.readUTF();
                }
                result = values;
            } else {
                result = stream.readUTF();
            }
        //ENUM
        } else if(wireType == ENUM) {
            //实际类型
            String className = stream.readUTF();
            String val = stream.readUTF();

            //创建实例
            Class cls = Class.forName(className);
            result = Enum.valueOf(cls, val);

        //COLLECTION LIST SET
        } else if(wireType == COLLECTION || wireType == LIST || wireType == SET) {
            //长度
            int len = stream.readInt();

            //类型
            Collection list;
            if(wireType == LIST) list = new ArrayList<>();
            else if(wireType == SET) list = new HashSet<>();
            else list = new ArrayList<>();  //未知Collection的具体实现 暂时一律使用arrayList子类的实现

            //填充数据
            for(int i = 0; i < len; i++) {
                list.add(read(stream));
            }
            result = list;

        //MAP
        } else if(wireType == MAP) {
            //长度
            int len = stream.readInt();

            //数据
            Map map = new LinkedHashMap<>();
            for(int i = 0; i < len; i++) {
                Object key = read(stream);
                Object val = read(stream);

                map.put(key, val);
            }

            result = map;

        //IDistributedSerilizable接口
        } else if(wireType == DISTRIBUTED) {
            //实际类型
            /*这种方式要提前生成常量池switch case(int)
            int id = stream.readInt();
            ISerilizable seriable = org.gof.core.CommonSerializer.create(id);
            if(seriable == null)
                seriable = _commonFunc.apply(id);
            seriable.readFrom(this);
            result = seriable;*/


            String className = stream.readUTF();
            Class<?> cls = Class.forName(className);

            //创建实例并加载数据
            Constructor<?> constructor = cls.getDeclaredConstructor();
            constructor.setAccessible(true);
            ISerilizable seriable = (ISerilizable)constructor.newInstance();
            seriable.readFrom(stream);
            result = seriable;
        //protobuf消息
        } else if(wireType == MSG) {

        //Object[]
        } else if(wireType == OBJECT && isArray) {
            Object[] values = new Object[arrayLen];
            for(int i = 0; i < arrayLen; i++) {
                values[i] = read(stream);
            }
            result = values;

        //其余一律不支持
        } else {
            throw new SysException("发现无法被反序列化的类型: wireType={}, isArray={}", wireType, isArray);
        }

        //返回值
        return (T) result;
    }
    /*write*/

    public static <T> T deserilize(byte[] data){
        ByteArrayInputStream in = new ByteArrayInputStream(data);
        DataInputStream stream = new DataInputStream(in);
        return read(stream);
    }
    /**
     * 连续读取Object到list
     */
    public static <T> List<T> deserilize2List(byte[] data){
        return deserilize2List(data, new ArrayList<>());
    }
    public static <T> List<T> deserilize2List(byte[] data, List<T> list){
        try (ByteArrayInputStream in = new ByteArrayInputStream(data);
                DataInputStream stream = new DataInputStream(in)){
            while(stream.available() > 0){
                T t = read(stream);
                list.add(t);
            }
            return list;
        } catch (Exception e) {
            LogCore.BASE.error("read file err:{}", e);
            return null;
        }
    }
    public static byte[] serlize(Object value) throws IOException {
        try(ByteArrayOutputStream bout = new ByteArrayOutputStream();
            DataOutputStream stream = new DataOutputStream(bout)) {
            writeObject(value, stream);
            return bout.toByteArray();
        } catch (Exception e) {
            throw new SysException(e, "OutputStream写入数据失败。");
        }
    }
    /**
     * 写入数据到流中
     * 仅支持
     * byte byte[] boolean boolean[] int int[] long long[] 
     * double double[] String String[] 
     * Enum枚举 List、Map两种包装类型
     * 以及实现了IDistributedSerilizable接口的类
     * @param value
     * @throws IOException
     */
    public static void write(Object value, DataOutputStream stream) {
        try {
            writeObject(value, stream);
        //不支持序列化化的错误 要对外汇报
        } catch (Exception e) {
            throw new SysException(e, "OutputStream写入数据失败。");
        }
    }

    /**
     * 写入数据到流中
     * 仅支持
     * byte byte[] boolean boolean[] int int[] long long[] 
     * double double[] String String[] 
     * Enum枚举 List、Map两种包装类型
     * 以及实现了IDistributedSerilizable接口的类
     * @param value
     * @throws IOException
     */
    static void writeObject(Object value, DataOutputStream stream) throws IOException {
        //空对象
        if(value == null) {
            stream.writeInt(NULL);
        }

        //数据类型
        Class<?> clazz = value.getClass();

        //BYTE
        if(clazz == byte.class || clazz == Byte.class) {
            stream.writeInt(BYTE);
            stream.writeByte((byte)value);
        } else if(clazz == byte[].class) {
            byte[] array = (byte[])value;
            stream.writeInt(BYTE | ARRAY);
            stream.writeInt(array.length);
            stream.write(array);
        //BOOLEAN
        } else if(clazz == boolean.class || clazz == Boolean.class) {
            stream.writeInt(BOOLEAN);
            stream.writeBoolean((boolean)value);
        } else if(clazz == boolean[].class) {
            boolean[] array = (boolean[])value;
            stream.writeInt(BOOLEAN | ARRAY);
            stream.writeInt(array.length);
            for(int i = 0; i < array.length; i++) {
                stream.writeBoolean(array[i]);
            }
        //INT
        } else if(clazz == int.class || clazz == Integer.class) {
            stream.writeInt(INT);
            stream.writeInt((int)value);
        } else if(clazz == int[].class) {
            int[] array = (int[])value;
            stream.writeInt(INT | ARRAY);
            stream.writeInt(array.length);
            for(int i = 0; i < array.length; i++) {
                stream.writeInt(array[i]);
            }
        //LONG
        } else if(clazz == long.class || clazz == Long.class) {
            stream.writeInt(LONG);
            stream.writeLong((long)value);
        } else if(clazz == long[].class) {
            long[] array = (long[])value;
            stream.writeInt(LONG | ARRAY);
            stream.writeInt(array.length);
            for(int i = 0; i < array.length; i++) {
                stream.writeLong(array[i]);
            }
        //FLOAT
        } else if(clazz == float.class || clazz == Float.class) {
            stream.writeFloat(FLOAT);
            stream.writeFloat((float)value);
        } else if(clazz == float[].class) {
            float[] array = (float[])value;
            stream.writeInt(FLOAT | ARRAY);
            stream.writeInt(array.length);
            for(int i = 0; i < array.length; i++) {
                stream.writeFloat(array[i]);
            }
        //DOUBLE
        } else if(clazz == double.class || clazz == Double.class) {
            stream.writeInt(DOUBLE);
            stream.writeDouble((double)value);
        } else if(clazz == double[].class) {
            double[] array = (double[])value;
            stream.writeInt(DOUBLE | ARRAY);
            stream.writeInt(array.length);
            for(int i = 0; i < array.length; i++) {
                stream.writeDouble(array[i]);
            }
        //STRING
        } else if(clazz == String.class) {
            stream.writeInt(STRING);
            stream.writeUTF((String)value);
        } else if(clazz == String[].class) {
            String[] array = (String[])value;
            stream.writeInt(STRING | ARRAY);
            stream.writeInt(array.length);
            for(int i = 0; i < array.length; i++) {
                stream.writeUTF(array[i]);
            }
        //ENUM
        } else if(value instanceof Enum) {
            Enum<?> val = (Enum<?>) value;
            stream.writeInt(ENUM);
            stream.writeUTF(val.getClass().getName());
            stream.writeUTF(val.name());

        //COLLECTION LIST SET
        } else if(value instanceof Collection) {
            Collection<?> val = (Collection<?>) value;

            //判断子类型
            int type;
            if(value instanceof List) type = LIST;
            else if(value instanceof Set) type = SET;
            else type = COLLECTION;

            stream.writeInt(type);
            stream.writeInt(val.size());

            for(Object o : val) {
                write(o, stream);
            }

        //MAP
        } else if(value instanceof Map) {
            Map<?,?> val = (Map<?,?>) value;

            stream.writeInt(MAP);
            stream.writeInt(val.size());

            for(Entry<?, ?> e : val.entrySet()) {
                Object k = e.getKey();
                Object v = e.getValue();
                write(k, stream);
                write(v, stream);
            }

        //IDistributedSerilizable接口
        } else if(value instanceof ISerilizable) {
            ISerilizable seriable = (ISerilizable)value;
            stream.writeInt(DISTRIBUTED);
            stream.writeInt(value.getClass().getName().hashCode());
            seriable.writeTo(stream);
        //protobuf消息
//      } else if(value instanceof Message) {
//          Message msg = (Message)value;
//          byte[] bytes = msg.toByteArray();
//          
//          stream.writeInt32NoTag(MSG);
//          stream.writeInt32NoTag(bytes.length);       //消息长度 不包括消息类型
//          stream.writeInt32NoTag(msg.getClass().getName().hashCode());
//          stream.writeRawBytes(bytes);

        //数组
        } else if(value instanceof Object[]) {
            Object[] array = (Object[])value;
            stream.writeInt(OBJECT | ARRAY);
            stream.writeInt(array.length);
            for(Object o : array) {
                write(o, stream);
            }
        //其余一律不支持
        } else {
            throw new SysException("发现无法被序列化的类型:{}", clazz.getName());
        }
    }
}

思考:如何处理循环引用的问题?在json的序列化和protocol的序列化中的循环引用是如何处理的?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值