当前位置: 首页 > news >正文

Java MessagePack序列化工具(适配Unity)

Java MessagePack序列化工具(适配Unity)

  • 前言
  • 项目
    • 代码编写

前言

前后端统一用MessagePack,结果序列化的结果不一样,发现C#侧需要给每个类增加描述字段数量的Head,而Java却不用,所以在Java侧封装一下序列化和反序列化方法,这样两边解析的内容就完全一致了。
序列化之后效果

项目

代码编写

感觉还有很大的压缩空间

import org.msgpack.core.MessageBufferPacker;
import org.msgpack.core.MessagePack;
import org.msgpack.core.MessageUnpacker;

import java.io.IOException;
import java.lang.reflect.*;
import java.util.*;

public class MessagePackSerializer {

    public static byte[] serialize(Object obj) throws IOException, IllegalAccessException {
        try (MessageBufferPacker packer = MessagePack.newDefaultBufferPacker()) {
            serializeObject(obj, packer);
            return packer.toByteArray();
        }
    }

    public static <T> T deserialize(byte[] data, Class<T> clazz) throws IOException, IllegalAccessException,
            InstantiationException, InvocationTargetException, NoSuchMethodException, ClassNotFoundException {
        try (MessageUnpacker unpacker = MessagePack.newDefaultUnpacker(data)) {
            return clazz.cast(deserializeObject(clazz, unpacker));
        }
    }

    private static void serializeObject(Object obj, MessageBufferPacker packer)
            throws IOException, IllegalAccessException {
        if (obj == null) {
            packer.packNil();
            return;
        }

        Class<?> clazz = obj.getClass();
        List<Field> allFields = new ArrayList<>();
        while (clazz != null) {
            Field[] fields = clazz.getDeclaredFields();
            allFields.addAll(Arrays.asList(fields));
            clazz = clazz.getSuperclass(); // 处理父类字段
        }

        packer.packArrayHeader(allFields.size());

        for (Field field : allFields) {
            field.setAccessible(true);
            Object value = field.get(obj);
            serializeValue(value, packer);
        }
    }

    private static Object deserializeObject(Class<?> clazz, MessageUnpacker unpacker) throws IOException,
            IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException,
            ClassNotFoundException {
        if (unpacker.tryUnpackNil()) {
            return null;
        }

        Object obj = clazz.getDeclaredConstructor().newInstance();

        int fieldCount = unpacker.unpackArrayHeader();

        List<Field> allFields = new ArrayList<>();
        while (clazz != null) {
            Field[] fields = clazz.getDeclaredFields();
            allFields.addAll(Arrays.asList(fields));
            clazz = clazz.getSuperclass();
        }

        for (int i = 0; i < fieldCount; i++) {
            Field field = allFields.get(i);
            field.setAccessible(true);
            Object value = deserializeValue(field.getType(), unpacker, getFieldGenericType(field));
            field.set(obj, value);
        }

        return obj;
    }

    private static void serializeValue(Object value, MessageBufferPacker packer)
            throws IOException, IllegalAccessException {
        if (value == null) {
            packer.packNil();
        } else if (value instanceof String) {
            packer.packString((String) value);
        } else if (value instanceof Integer) {
            packer.packInt((Integer) value);
        } else if (value instanceof Long) {
            packer.packLong((Long) value);
        } else if (value instanceof Float) {
            packer.packFloat((Float) value);
        } else if (value instanceof Double) {
            packer.packDouble((Double) value);
        } else if (value instanceof Boolean) {
            packer.packBoolean((Boolean) value);
        } else if (value instanceof List) {
            List<?> list = (List<?>) value;
            packer.packArrayHeader(list.size());
            for (Object item : list) {
                serializeValue(item, packer);
            }
        } else if (value instanceof Map) {
            Map<?, ?> map = (Map<?, ?>) value;
            packer.packMapHeader(map.size());
            for (Map.Entry<?, ?> entry : map.entrySet()) {
                serializeValue(entry.getKey(), packer);
                serializeValue(entry.getValue(), packer);
            }
        } else {
            serializeObject(value, packer);
        }
    }

    private static Object deserializeValue(Class<?> type, MessageUnpacker unpacker, Type genericType)
            throws IOException, IllegalAccessException, InstantiationException, InvocationTargetException,
            NoSuchMethodException, ClassNotFoundException {
        if (unpacker.tryUnpackNil()) {
            return null;
        } else if (type == String.class) {
            return unpacker.unpackString();
        } else if (type == Integer.class || type == int.class) {
            return unpacker.unpackInt();
        } else if (type == Long.class || type == long.class) {
            return unpacker.unpackLong();
        } else if (type == Float.class || type == float.class) {
            return unpacker.unpackFloat();
        } else if (type == Double.class || type == double.class) {
            return unpacker.unpackDouble();
        } else if (type == Boolean.class || type == boolean.class) {
            return unpacker.unpackBoolean();
        } else if (List.class.isAssignableFrom(type)) {
            int size = unpacker.unpackArrayHeader();
            List<Object> list = new ArrayList<Object>(size);
            for (int i = 0; i < size; i++) {
                Type listItemType = (genericType instanceof ParameterizedType)
                        ? ((ParameterizedType) genericType).getActualTypeArguments()[0]
                        : Object.class;
                list.add(deserializeValue((Class<?>) listItemType, unpacker, listItemType));
            }
            return list;
        } else if (Map.class.isAssignableFrom(type)) {
            int size = unpacker.unpackMapHeader();
            Map<Object, Object> map = new HashMap<Object, Object>(size);
            Type keyType = (genericType instanceof ParameterizedType)
                    ? ((ParameterizedType) genericType).getActualTypeArguments()[0]
                    : String.class;
            Type valueType = (genericType instanceof ParameterizedType)
                    ? ((ParameterizedType) genericType).getActualTypeArguments()[1]
                    : Object.class;
            for (int i = 0; i < size; i++) {
                Object key = deserializeValue((Class<?>) keyType, unpacker, keyType);
                Object value = deserializeValue((Class<?>) valueType, unpacker, valueType);
                map.put(key, value);
            }
            return map;
        } else {
            return deserializeObject(type, unpacker);
        }
    }

    private static Type getFieldGenericType(Field field) {
        return field.getGenericType();
    }
}

如果有优化会放到下面这个地址
JavaMsgPack-Utility

相关文章:

  • 动态规划(一)
  • 如何优化 Vite 项目中的 Lodash 引入:从 Tree Shaking 到自动化测试
  • Linux权限管理
  • kvm压缩虚拟机磁盘
  • 了解Android
  • DVWA综合靶场漏洞讲解
  • python 异常处理
  • 在Windows11强制开启copilot
  • 独立站PrestaShop安装
  • 获取当前路由器的外网IP(WAN IP)
  • 电脑硬盘坏了怎么恢复数据?
  • 蓝桥杯2021第十二届蓝桥杯青少年组省赛试题真题
  • Vue3重置reactive变量造成循环引用导致JSON.stringify语法报错
  • python之matplotlib (1 介绍及基本用法)
  • vin查询汽车品牌-vin查询汽车品牌接口-车辆信息查询接口
  • ubuntu中python 改为默认使用python3,pip改为默认使用pip3
  • 【个人学习】JVM(7):方法区概述、方法区内部结构、垃圾回收等
  • 什么是光伏电站气象站——气象监测
  • YoloV9改进策略:下采样与上采样改进|下采样模块和DUpsampling上采样模块|即插即用
  • Linux安装MQTT 服务器(图文教程)
  • 治沙“异瞳”男生疑似摆拍,团队称合作12天多期视频为策划拍摄
  • 经济日报整版聚焦“妈妈岗”:就业路越走越宽,有温度重实效
  • 正荣地产:前4个月销售14.96亿元,控股股东已获委任联合清盘人
  • 国防部:正告菲方停止以任何方式冲撞中方核心利益
  • 老铺黄金拟配售募资近27亿港元,用于门店拓展扩建及补充流动资金等
  • 对话哭泣照被恶意盗用成“高潮针”配图女生:难过又屈辱