在java中,正常来说序列化是可以直接继承Serializable
,或使用类似于fastjson, protobuf等框架。
但是这些框架对于二进制协议,自定义协议,私有协议方面却不太好使,私有协议大多还是按照字节的方式组织数据,对于java来说需要控制每个属性的序列化方式,
所以这块主要还是以传统的方式,读字节流开始,按照字节读取并填充对象。
这里给大家推一个好用的框架Magic-byte
, 这个可以很方便的控制字节序列化方式进而实现私有协议;
比如以下代码:
// declare class must use public
// 使用大端模式, 默认为大端
@MagicClass(byteOrder = ByteOrder.BIG_ENDIAN)
public class School {
// 10 byte, 普通数据类型, 占用10字节长度
@MagicField(order = 1, size = 10)
private String name;
// 2 byte, 长度字段, 数据序列化时将自动填充实际数据长度
@MagicField(order = 3, calcLength = true)
private short length;
// 支持组合模式, 这里嵌入了 Student 对象
// 总字节数 = students.bytes * length
@MagicField(order = 5, size = 2)
private Student[] students;
// 0 byte, 注意, 此处无法序列化, 不支持的数据类型将会被忽略
@MagicField(order = 7)
private List<Object> notSupport;
// 0 byte, 注意, 此处无法序列化, 不支持的数据类型将会被忽略
@MagicField(order = 9)
private Object age;
// 4 byte, 注意, 此处指定为秒级时间戳, 同时指定使用4个字节保存, 未指定则默认6个字节
@MagicField(order = 13, size = 4, timestampFormat = TimestampFormatter.TO_TIMESTAMP_SECONDS)
private Date[] birthdays;
// 1 byte, 普通数据类型, 通过order配置序列化顺序, 序列号顺序和定义顺序无关
@MagicField(order = 15)
private byte age;
// 1 byte, 校验和字段, 序列化时如提供计算函数则将会自动填充
@MagicField(order = 17)
private byte checkCode;
// getter and setter ...
}
@MagicClass()
public class Student {
// 10 byte, 普通数据, 长度为 10 字节
@MagicField(order = 1, size = 10)
private String name;
// 4 byte, 普通数据, 整数, 此字段决定后续 phones 字段长度
@MagicField(order = 5)
private int length;
// 总字节数 = phones.size * length
// 单个元素 8 byte, 此List并未直接指定大小, 大小由 length 字段决定. length字段数据类型只能为 byte, short, int, UNumber
@MagicField(order = 10, dynamicSizeOf = "length")
private List<Long> phones;
// 1 byte
@MagicField(order = 15)
private byte age;
// 生日, 这里为秒级时间戳, 指定使用4个字节, 日期类型未指定则默认6个字节
@MagicField(order = 18, size = 4, timestampFormat = TimestampFormatter.TO_TIMESTAMP_SECONDS)
private Date birthDay;
// getter and setter ...
}
public class Hello {
void main() {
// 全局配置校验和计算函数
MagicByte.configMagicChecker(Checker::customChecker);
School school = new School();
school.setAge((byte) 23);
// you can set other propertis
// object to bytes
// 也可以单独传入计算函数
byte[] bytes = MagicByte.unpack(school, Checker::customChecker);
School school2 = MagicByte.pack(bytes, School.class); // bytes to object
System.out.println(school.getAge() == school2.getAge()); // out put true
}
}
public class Checker {
/**
* 序列化时: data数据中包含所有已序列化的数据(包括 calcLength 也已经调用并序列化)
* 反序列化时: data数据为传入数据的副本
* @param data
* @return
*/
public static byte[] customChecker(byte[] data) {
return new byte[]{0xff};
}
}
上面代码是直接从开始页copy过来的,不过确实用起来很方便,安利给大家哈
maven引入,新版本大家可以去github主页看
<dependency>
<groupId>io.github.misterchangray</groupId>
<artifactId>magic-byte</artifactId>
<version>2.4.1</version>
</dependency>
标签:JAVA,字节,自定义,private,MagicField,byte,序列化,order
From: https://www.cnblogs.com/raychang/p/17889470.html