java对象序列化byte[]

该工具致力于解决物联网行业中自定义二进制协议解析的挑战,提供了一种用于二进制与JavaBean互相转换的解决方案。通过注解配置,支持对象组合嵌套,支持多种数据类型,包括对字符串长度的动态调整。同时,提供了序列化和反序列化方法,简化了处理自定义二进制协议的过程。此外,还提供了一个动态修改注解工具类,用于在运行时改变注解的属性值。
摘要由CSDN通过智能技术生成

1.简介

本工具解决在自定义二进制协议中二进制和javaBean相互转换的问题; 在当代物联网行业中, 更多的公司选择使用自定义的二进制协议; JAVA同学在对这些协议进行解析时,会陷入序列化/反序列化的痛苦循环中;解决了自定义二进制协议的以下痛点:

  1. 二进制协议解析
  2. 效验计算
  3. 位运算难
  4. JAVA对象转换
  5. 无符号运算操作

maven项目可直接导入

<dependency>
    <groupId>io.github.misterchangray</groupId>
    <artifactId>magic-byte</artifactId>
    <version>2.1.0</version>
</dependency>
  1. 引入Jar包;
  2. @MagicClass对当前类进行全局配置
  3. @MagicField对需要转换的JAVA对象属性进行标注,支持对象组合嵌套
  4. 使用MagicByte.pack()或则MagicByte.unpack()对数据或对象进行快速的序列化或反序列化
4. 注解和属性说明

工具存在两个注解:

  1. @MagicClass()
    

    类注解; 主要用于数据全局配置

    • byteOrder 配置序列化大小端
    • strict 严格模式, 默认false, 严格模式将会抛出更多的异常
  2. @MagicField()
    

    属性注解, 未注解的属性不参与序列化/反序列化过程

    • order 定义序列化顺序**(重要, 投入使用后请勿修改, 从1开始依次递增)**
    • size 属性大小, 仅String和List需要设置, String 代表字节长度, List和Array代表成员长度
    • charset 字符集设置, 仅String设置有效; 默认ASCII
    • dynamicSize 标记字段为动态长度, 整个数据结构只能标记一次且仅能标记String&List&Array类型字段
    • dynamicSizeOf 从指定的 order 中获取List或Array的长度, 仅List,Array,String有效;引用字段类型只能为byte, short, int
    • calcLength 标记字段为长度字段, 反序列化时将自动将长度填充到此字段; 可能抛出: InvalidLengthException
    • calcCheckCode 标记字段为校验和字段, 序列化或反序列化时将会校验或自动填充; 可能抛出: InvalidCheckCodeException
5. 支持的数据类型及字节大小;
数据类型数据类型字节大小
byteboolean1
shortchar2
intfloat4
longdouble8
Stringcustom

6.String类型size问题,可以使用代理动态改变注解的size的value值
实体


import com.github.misterchangray.core.annotation.MagicClass;
import com.github.misterchangray.core.annotation.MagicField;
import com.github.misterchangray.core.enums.ByteOrder;
import lombok.Data;
import lombok.experimental.Accessors;

import java.io.Serializable;

@Data
@MagicClass(byteOrder = ByteOrder.BIG_ENDIAN)
@Accessors(chain = true)
public class ConnectionStruct implements Serializable {
    @MagicField(order = 1)
    private String ProId;
    @MagicField(order = 2)
    private String SegId;

    @MagicField(order = 3)
    private String Type;
    @MagicField(order = 4)
    private String Depth;
    @MagicField(order = 5)
    private String Height;
    @MagicField(order = 6)
    private String Layer;
    @MagicField(order = 7)
    public String VehicleType;
    @MagicField(order = 8)
    public String VehicleNo;
    @MagicField(order = 9)
    public String DeviceNo;
}

动态修改注解工具类

import io.swagger.models.auth.In;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/*
 * 思路:
 * 1、先获取需要修改的 Field
 * 2、通过 Field 的方法 getDeclaredField 获取需要修改的注解
 * 3、Proxy.getInvocationHandler(anno) 获取该注解代理实例所持有的 InvocationHandler
 * 4、获取 AnnotationInvocationHandler 的 memberValues 字段
 * 5、获取 memberValuesMap,通过该Map 对注解属性值获取修改
 *
 * @Param dest : 需要修改的对象
 * @Param changeProperties : 类属性下注解需要修改的集合
 */
public class DynamicChangeAnnoUtils {
    public static void changeAnnoValue(Object dest, Map<String, HashMap<String, Map<String, Map<String, Integer>>>> changeProperties) {
        System.out.println(changeProperties+"1");
        for (String filedKey: changeProperties.keySet()) {
            System.out.println("filedKey=" + filedKey+"2");
            try {
                Field field = dest.getClass().getDeclaredField(filedKey);
                System.out.println(field.getName()+"3");
                String name = field.getName();
                for (String annoKey : changeProperties.get(filedKey).keySet()) {
                    //获取字段上的注解实例
                    Annotation[] annotations = field.getDeclaredAnnotations();
                    for (Annotation anno : annotations) {
                        if (anno.annotationType().getSimpleName().equals(annoKey)) {
//                            System.out.println(anno.annotationType().getSimpleName());
                            // 1、获取代理实例所持有的 InvocationHandler
                            InvocationHandler handler = Proxy.getInvocationHandler(anno);
                            // 2、获取 AnnotationInvocationHandler 的 memberValues 字段
                            Field mValuesField = handler.getClass().getDeclaredField("memberValues");
                            // 3、打开访问权限
                            mValuesField.setAccessible(true);
                            // 4、获取 memberValuesMap
                            Map memberValuesMap = (Map) mValuesField.get(handler);
                            // 5、put修改注解属性值
                            System.out.println(  changeProperties.get(filedKey).get(annoKey));
                            changeProperties.get(filedKey).get(annoKey).forEach((k, v) -> {
                                System.out.println("k=" + k + ",v=" + v.get(name)+"----4");
                                for(String key:v.keySet()){
                                    Integer value = v.get(key).intValue();
                                    System.out.println("key="+key+" vlaue="+value);
                                    if (key.equals(name)){
                                        memberValuesMap.put(k, value);
                                    }
                                }
                            });
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    public static void printAnno(Object obj) {
        // 遍历获取Field[] 集合
        Field[] declaredFields = obj.getClass().getDeclaredFields();
        for (Field f : declaredFields) {
            // 遍历获取Annotation[] 集合
            Annotation[] annotations = f.getDeclaredAnnotations();
            for (Annotation anno : annotations) {
//                System.out.println(anno);  //@com.ymqx.动态修改类属性的注解值.TestAnno(name=test, type=1)
                //System.out.println(anno.annotationType().getName());  //com.ymqx.动态修改类属性的注解值.TestAnno
                //System.out.println(anno.annotationType().getSimpleName());  //TestAnno

                if (anno.annotationType().getSimpleName().equals("MagicField")) {
                    // 1、获取代理实例所持有的 InvocationHandler
                    InvocationHandler handler = Proxy.getInvocationHandler(anno);
                    try {
                        // 2、获取 AnnotationInvocationHandler 的 memberValues 字段
                        Field mValuesField = handler.getClass().getDeclaredField("memberValues");
                        // 3、打开访问权限
                        mValuesField.setAccessible(true);
                        // 4、获取 memberValuesMap
                        Map memberValuesMap = (Map) mValuesField.get(handler);
                        // 5、get获取注解属性值
                        System.out.println(memberValuesMap.get("size"));
//                        System.out.println(memberValuesMap.get("type"));
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    public static int getWordCount(String s) {
        int length = 0;
        for (int i = 0; i < s.length(); i++) {
            int ascii = Character.codePointAt(s, i);
            if (ascii >= 0 && ascii <= 255)
                length++;
            else
                length += 2;
        }
        return length;
    }
}


使用

   public static void test() throws Exception {
        ConnectionStruct connection2 = new ConnectionStruct();
        //xxxxxxx中文字符串
        connection2.setProId(HexUtils.str2HexStr("xxxxxxx"));
        connection2.setSegId(HexUtils.str2HexStr("二xxxxxxx"));
        connection2.setType(HexUtils.str2HexStr("xxxxxxx"));
        connection2.setHeight(HexUtils.str2HexStr("xxxxxxx"));
        connection2.setDepth(HexUtils.str2HexStr("xxxxxxx"));
        connection2.setLayer(HexUtils.str2HexStr("xxxxxxx"));
        connection2.VehicleType = HexUtils.str2HexStr("xxxxxxx");
        connection2.VehicleNo = HexUtils.str2HexStr("xxxxxxx");
        connection2.DeviceNo = HexUtils.str2HexStr("xxxxxxx");
        //一种方式转Byte
//        ByteBuffer byteBuffer = ByteBuffer.allocate(connection.getProId().getBytes().length).order(ByteOrder.BIG_ENDIAN);
//        byteBuffer.put(connection.getProId().getBytes());
//        byte[] tmp = byteBuffer.array();
        int ProIdCount = DynamicChangeAnnoUtils.getWordCount(connection2.getProId());
        int SegIdCount = DynamicChangeAnnoUtils.getWordCount(connection2.getSegId());
        int DepthCount = DynamicChangeAnnoUtils.getWordCount(connection2.getDepth());
        int TypeCount = DynamicChangeAnnoUtils.getWordCount(connection2.getType());
        int HeightCount = DynamicChangeAnnoUtils.getWordCount(connection2.getHeight());
        int LayerCount = DynamicChangeAnnoUtils.getWordCount(connection2.getLayer());
        int VehicleTypeCount = DynamicChangeAnnoUtils.getWordCount(connection2.getVehicleType());
        int VehicleNoCount = DynamicChangeAnnoUtils.getWordCount(connection2.getVehicleNo());
        int DeviceNoCount = DynamicChangeAnnoUtils.getWordCount(connection2.getDeviceNo());

        HashMap<String, Map<String, Integer>> annoValueMap = new HashMap<>();
        HashMap<String, Integer> stringIntegerHashMap = new HashMap<>();
        stringIntegerHashMap.put("ProId", ProIdCount);
        stringIntegerHashMap.put("SegId", SegIdCount);
        stringIntegerHashMap.put("Type", TypeCount);
        stringIntegerHashMap.put("Depth", DepthCount);
        stringIntegerHashMap.put("Height", HeightCount);
        stringIntegerHashMap.put("Layer", LayerCount);
        stringIntegerHashMap.put("VehicleType", VehicleTypeCount);
        stringIntegerHashMap.put("VehicleNo", VehicleNoCount);
        stringIntegerHashMap.put("DeviceNo", DeviceNoCount);

        annoValueMap.put("size", stringIntegerHashMap);
        HashMap<String, Map<String, Map<String, Integer>>> annoMap = new HashMap<>();
        annoMap.put("MagicField", annoValueMap);
        HashMap<String, HashMap<String, Map<String, Map<String, Integer>>>> filedMap = new HashMap<>();
        filedMap.put("ProId", annoMap);
        filedMap.put("SegId", annoMap);
        filedMap.put("Type", annoMap);
        filedMap.put("Depth", annoMap);
        filedMap.put("Height", annoMap);
        filedMap.put("Layer", annoMap);
        filedMap.put("VehicleType", annoMap);
        filedMap.put("VehicleNo", annoMap);
        filedMap.put("DeviceNo", annoMap);
        System.out.println("+++修改注解属性值后+++");
        DynamicChangeAnnoUtils.changeAnnoValue(connection2, filedMap);
        DynamicChangeAnnoUtils.printAnno(connection2);
        byte[] tmp = MagicByte.unpackToByte(connection2);    // 对象序列化到字节
        String s = HexUtils.byte2HexStr(tmp);
        String s1 = HexUtils.hexStr2Str(s);
        String s2 = HexUtils.hexStr2Str(s1);//中文再次转换
        System.out.println(s2);
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

北996

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值