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

news2024/9/20 14:24:53

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2049184.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

51系列LY-51S出现下载失败·的解法

1.他的下载电路是特殊设计的 一般连接1&#xff0c;2&#xff0c;另外的接口2&#xff0c;3一般不接&#xff0c;而且2&#xff0c;3的功能是用来diy自动下载电路的&#xff0c;你接上2&#xff0c;3又没独特的下载电路会一直复位

进程池详解

目录 进程池 1、什么是进程池&#xff1f; 2、实现进程池 &#xff08;1&#xff09;相关函数&#xff1a; pipe函数&#xff1a; write函数 read函数 waitpid函数 &#xff08;2&#xff09;代码实现面向过程进程池 Task.hpp processPool.cc 3、注意事项 进程池 …

坚鹏讲人才第12期:引领数字化未来—数字化人才与导师共赢之路

坚鹏讲人才第12期&#xff1a;引领数字化未来—数字化人才与导师共赢之路 ——抢占名额先机 成为坚鹏弟子 加速数字化转型 数字化浪潮汹涌而至&#xff0c;你是否感到迷茫、困惑、焦虑&#xff1f;想不想一脚油门冲进未来&#xff0c;和我一同探寻数字化人才的奥秘&#xf…

【迅为电子】RK3568驱动指南|第十七篇 串口-第202章 串口编程

瑞芯微RK3568芯片是一款定位中高端的通用型SOC&#xff0c;采用22nm制程工艺&#xff0c;搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码&#xff0c;支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU&#xff0c;可用于轻量级人工…

计算机毕业设计选什么题目好?基于vue的音乐播放系统

✍✍计算机毕业编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java、…

LangGraph Studio:首款智能体(agent)IDE

0 前言 LangGraph Studio 提供了一个专门的智能体IDE&#xff0c;用于可视化、交互和调试复杂的智能体应用程序。本文来了解如何在桌面使用。 LLM为新型智能体应用程序的发展铺平了道路——随这些应用程序演进&#xff0c;开发它们所需工具也必须不断改进。今天推出的 LangG…

C++(10)类语法分析(1)

C(10)之类语法分析(1) Author: Once Day Date: 2024年8月17日 一位热衷于Linux学习和开发的菜鸟&#xff0c;试图谱写一场冒险之旅&#xff0c;也许终点只是一场白日梦… 漫漫长路&#xff0c;有人对你微笑过嘛… 全系列文章可参考专栏: 源码分析_Once-Day的博客-CSDN博客 …

JavaFX布局-DialogPane

JavaFX布局-DialogPane 常用属性标题区域headerTextheader 内容区域contentTextcontent graphic按钮设置expandableContent 实现方式Java实现 一个特殊的布局容器&#xff0c;常用于弹出框&#xff0c;与Dialog配合一起使用包含标题区&#xff0c;内容区域&#xff0c;扩展区域…

Merkle树(Merkle Tree):高效地验证某个数据块是否包含在数据集中

目录 Merkle树(Merkle Tree) 一、基本结构 二、构建过程 三、主要作用 四、应用领域 Merkle树(Merkle Tree) Merkle树(Merkle Tree),也被称为默克尔树或Merkle哈希树,是一种基于哈希的数据结构,主要用于验证大规模数据集的完整性和一致性。它的名字来源于其发明…

【Unity教程】使用 Animation Rigging实现IK制作程序化的动画

在 Unity 开发中&#xff0c;为角色创建逼真且自适应的动画是提升游戏体验的关键。在本教程中&#xff0c;我们将结合 Animation Rigging 工具和 IK&#xff08;Inverse Kinematics&#xff0c;反向运动学&#xff09;插件来实现程序化的动画。 视频教程可以参考b战大佬的视频 …

不只是翻译,更是智慧碰撞!有道翻译与3大强敌的全方位较量

现在的科技牛得不行&#xff0c;翻译软件早就成了咱们学习、工作、生活里少不了的帮手。它们不光是把语言的墙给推倒了&#xff0c;还让咱们说话交流快多了。今儿个&#xff0c;咱们就一块儿瞧瞧2024年的翻译软件圈子&#xff0c;瞅瞅那几个最火的翻译工具&#xff0c;它们怎么…

生信软件30 - 快速单倍型分析工具merlin

Merlin可用于连锁分析或关联分析、IBD和亲缘关系估计、单倍型分析、错误检测和模拟。 1. merlin下载 下载地址&#xff1a; http://csg.sph.umich.edu/abecasis/merlin/download/ # linux版本 wget http://csg.sph.umich.edu/abecasis/merlin/download/Linux-merlin.tar.gz …

如何在本地和远程删除 Git 分支?

如何在本地和远程删除 Git 分支&#xff1f; 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#xff0c;我是博主英杰&#xff0c;211科班出身&#xff0c;就职于医疗科技公司&#xff0c;热衷分享知识&#xff0c;武汉城市开发者社区主理人 擅长.n…

创新赛场的制胜法宝:如何让你的商业计划书脱颖而出

创新赛场的制胜法宝&#xff1a;如何让你的商业计划书脱颖而出 前言明确产品或服务的核心功能突出创新性用户需求和市场痛点具体示例和场景详细描述产品和服务的方法实例化产品与服务视觉辅助工具未来展望结语 前言 作为一名资深的项目负责人&#xff0c;我有幸参与了无数次创新…

React + Vite项目别名配置

Node版本&#xff1a;v20.16.0Vite版本&#xff1a;5.4.1 安装 types/node 依赖包 pnpm i types/node -D pnpm ls types/node配置 vite.config.js 文件: resolve: {alias: {"": join(__dirname, "./src/"),}, },使用配置好的别名 &#xff1a; 由上图我们…

考试:操作系统知识(02)

进程同步和互斥 临界资源&#xff1a;各进程间需要以互斥方式对其进行访问的资源。 临界区&#xff1a;指进程中对临界资源实施操作的那段程序。本质是一段程序代码。 ◆互斥&#xff1a;某资源(即临界资源) 在同一时间内只能由一个任务单独使用&#xff0c;使用时需要加锁&…

kafka连接图形化工具(Offset Explorer和CMAK)

kafka连接图形化工具 1、Offset Explorer1.1、下载Offset Explorer1.2、安装Offset Explorer1.3、配置Offset Explorer连接kafka 2、CMAK&#xff08;kafka的web管理后台&#xff09;2.1、下载2.2、解压安装2.3、配置2.4、启动2.5、CMAK访问 1、Offset Explorer Offset Explor…

【数据结构】二叉树链式结构(c语言)(附源码)

&#x1f31f;&#x1f31f;作者主页&#xff1a;ephemerals__ &#x1f31f;&#x1f31f;所属专栏&#xff1a;数据结构 目录 前言 一、节点的定义 二、创建一棵二叉树 1. 创建新节点 2. 手动创建二叉树 三、方法的声明 四、方法的实现 1. 前、中、后序遍历 1.1 前…

libLZMA库iOS18平台编译

1.下载xz源码: 使用autogen.sh生成configure文件 2.生成makefile rm -rf ./build/iOS && mkdir -p ./build/iOS && cd ./build/iOS && ../../configure --host=arm-apple-darwin64 --prefix=`pwd`/Frameworks/lzma CC="xcrun -sdk iphoneos cl…

二十天刷leetcode【hot100】算法- day2[前端Typescript]

指针 6.三数之和 给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0 。请你返回所有和为 0 且不重复的三元组。 注意&#xff1a;答案中不可以包含重复的…