java | c结构体转java实体类 字节 --- 绝版彩蛋
一、前言
在与c通讯时,因语言只有结构体的概念,在与java进行socket通信时,java往往需要把接收到的字节流在处理成需要的数据,这一步我看网络上大部分都没有一个好用东东,因此分享出来。
注意:c的结构体自己了解去,这里不再叙述,同时c常用类型占几字节也务必清楚,这里不再叙述。
主要思想:根据c结构体的类型占位,自定义注解标注占位数,之后通过java反射直接生成对象。这里面主要基础基础就是反射、注解、字节进制这些东东,这些理解了可以根据自己业务去封装自己需要的。
还有 博主比较佛系,有些问题可能不会回复
二、自定义注解
里面有一些根据业务自定义一些业务逻辑,根据自己需要去修改。
StructRecv 结构报文 --- 与 c结构体对应。
import java.lang.annotation.*;
/**
* 结构报文 --- 与 c结构体对应
* 标记在类上
* <p>
* 默认支持
* 请求 类型映射 byte[] -> int、long、String、LocalDateTime、class、boolean(0.false 1.true)
* 响应 类型映射 int、long、LocalDateTime、String、class、boolean -> byte[]
* </p>
* <p>
* 支持继承(有父类情况下,优先解析父类的)
* 实体类对象必须要有无参构造
* 如果 字段为 class 不可 继承
* 如果有子类,那么对应 value 用 0 表示 ,会 动态计算出子类的大小 class、list
* </p>
*
* @author wbw
* @date 2020年8月1日09:16:53
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface StructRecv {
/**
* 结构体 每个字段所占 字节数
* <p>
* 如果字段为 class 那么必须包含
* 如果带有 0 则视为list
* </p>
*
* @return int[]
*/
int[] value();
/**
* 描述
*
* @return String
*/
String desc() default "";
/**
* 模块
*
* @return 模块类型
*/
ModuleTypeEnum module() default ModuleTypeEnum.IGNORE;
/**
* 策略标识
*
* @return 策略
*/
int policy() default 0;
/**
* 策略子类型
*
* @return PolicySubtypeEnum
*/
PolicySubtypeEnum subtypeEnum() default PolicySubtypeEnum.NONE;
/**
* 含有内部类 - 成员变量类
*
* @return false
*/
boolean hasInnerClass() default false;
/**
* 日志类型
*
* @return String
*/
String logType() default "";
}
StructRecvField 自定义 结构体 字段 类型
import com.hbcloud.hbx.audit.centre.common.constant.RecvFieldTypeEnum;
import java.lang.annotation.*;
/**
* 自定义 结构体 字段 类型
* 标记在字段上
*
* @author wbw
* @date 2020年8月1日09:17:01
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface StructRecvField {
/**
* 字段类型
* 默认为忽略字段
*
* @return 报文字段类型
*/
RecvFieldTypeEnum value() default RecvFieldTypeEnum.IGNORE;
/**
* list bean 对象
* <p>只有发时存在</p>
*
* @return class
*/
Class<?> bean() default Object.class;
/**
* list 字段
* <p>只有发时存在</p>
*
* @return class
*/
String field() default "";
/**
* list 数量
* <p>只有收时存在</p>
* <p>支持直接数字定义、支持自定义当前类字段</p>
*
* @return 数量
*/
String count() default "";
/**
* 需要计算进去的 frameLength
*
* @return 0
*/
int frameLength() default 0;
}
三、解析生成实体与解析成字节数组工具类
ByteUtil 字节工具类,这里如果对二进制转换不理解请自行百度
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import lombok.experimental.UtilityClass;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;
/**
* 字节工具类,提供字节转换等方法
* <p>
* 二进制位逢二进一
* 1 1 1 1 1 1 0 1 = 256 + 128 + 64 + 32 + 16 + 8 + 4 + 0 + 1 = 253
* </p>
* <p>
* 这里 | 和 & 均是 二进制运算法
* 把对应的数字 转换成二进制 在把运算符带入 即是结果
* 如 8 | 9 | 12 = 0000 1000 | 0000 1001 | 0000 1100 = 0000 1101 = 8 + 4 + 1 = 13
* 如 8 & 9 & 12 = 0000 1000 & 0000 1001 & 0000 1100 = 0000 1000 = 8
* <p>
* 同时 << 和 >> 均为移动符号 左边为乘 右边为除
* 如: 1 << 3 = 1 * 2 * 2 * 2 = 0000 0001 << 0000 1000 = 8
* </p>
*
* @author wbw
* @date 2020年8月1日11:13:01
*/
@UtilityClass
public class ByteUtil {
/**
* 补码使用
* 0xff = 255 = 1111 1111
*/
private final short FRAME = 0xFF;
/**
* 数字 转 bytes
*
* @param value 值
* @param src 源
* @param start 开始
* @param len 长度
*/
public void toBytes(long value, byte[] src, int start, int len) {
if (ArrayUtil.isEmpty(src) || src.length < len) {
return;
}
for (int i = 0; i < len; i++) {
src[start + i] = (byte) ((value >> (8 * i)) & FRAME);
}
}
/**
* 字段串 转 bytes
* 默认 utf-8
*
* @param value 值
* @param src 源
* @param start 开始
*/
public void toBytes(String value, byte[] src, int start) {
ByteUtil.toBytes(value, src, start, StandardCharsets.UTF_8);
}
/**
* 字段串 转 bytes 默认 gbk
*
* @param value 值
* @param src 源
* @param start 开始
*/
public void toBytesGbk(String value, byte[] src, int start) {
ByteUtil.toBytes(value, src, start, Charset.forName(CharsetUtil.GBK));
}
public void toBytes(String value, byte[] src, int start, Charset charset) {
if (StrUtil.isEmpty(value) || ArrayUtil.isEmpty(src)) {
return;
}
byte[] valBytes = value.getBytes(charset);
System.arraycopy(valBytes, 0, src, start, valBytes.length);
}
/**
* bytes 转 字符串
*
* @param bytes 源
* @param start 开始
* @param len 长度
* @param charset 编码
* @return String
*/
public String toString(byte[] bytes, int start, int len, String charset) {
if (ArrayUtil.isEmpty(bytes) || start + len > bytes.length) {
return "";
}
byte[] res = new byte[len];
System.arraycopy(bytes, start, res, 0, len);
return StrUtil.str(res, charset).trim();
}
/**
* bytes 转 字符串 默认 utf-8
*
* @param bytes 源
* @param start 开始
* @param len 长度
* @return String
*/
public String toString(byte[] bytes, int start, int len) {
return ByteUtil.toString(bytes, start, len, CharsetUtil.UTF_8);
}
/**
* 时间特殊处理 yyyy-mm-dd hh:mm:ss
*
* @param bytes 字节
* @param start 起始位置
* @return 时间
*/
public String toTime(byte[] bytes, int start) {
List<Integer> time = new LinkedList<>();
time.add(ByteUtil.toInt(bytes, start, 2));
time.add(ByteUtil.toInt(bytes, start + 4, 2));
time.add(ByteUtil.toInt(bytes, start + 6, 2));
time.add(ByteUtil.toInt(bytes, start + 8, 2));
time.add(ByteUtil.toInt(bytes, start + 10, 2));
time.add(ByteUtil.toInt(bytes, start + 12, 2));
Object[] array = time.stream()
.map(e -> e.toString().length() > 1 ? e.toString() : '0' + e.toString())
.toArray();
return String.format("%4s-%2s-%2s %2s:%2s:%2s", array);
}
/**
* bytes 转 字符串 默认 gbk
*
* @param bytes 源
* @param start 开始
* @param len 长度
* @return String
*/
public String toStringGbk(byte[] bytes, int start, int len) {
return ByteUtil.toString(bytes, start, len, CharsetUtil.GBK);
}
public long toLong(byte[] bytes, int start, int len) {
if (ArrayUtil.isEmpty(bytes) || start + len > bytes.length) {
return 0L;
}
long result = 0;
for (int i = 0; i < len; i++) {
result |= (bytes[start + i] & FRAME) << (i * 8);
}
return result;
}
public int toInt(byte[] bytes, int start, int len) {
return Math.toIntExact(ByteUtil.toLong(bytes, start, len));
}
/**
* 反的
*
* @param bytes 源
* @param start 开始
* @param len 长度
* @return int
*/
public int toIntReverse(byte[] bytes, int start, int len) {
if (ArrayUtil.isEmpty(bytes) || start + len > bytes.length) {
return 0;
}
int result = 0;
for (int i = len - 1, location = 0; i >= 0; i--) {
result |= (bytes[start + location++] & FRAME) << (i * 8);
}
return result;
}
}
StructRecvUtil 反射解析生成实体类
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.net.NetUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import lombok.SneakyThrows;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
/**
* tio 工具类
*
* @author wbw
* @date 2020/7/31 14:52
*/
@UtilityClass
@Slf4j
public class StructRecvUtil {
/**
* 默认支持的类型
*/
private final String HBX_TYPE = "com.xxx.xxx";
private final String STRING_TYPE = "string";
private final String INT_TYPE = "int";
private final String LONG_TYPE = "long";
private final String DATE_TYPE = "date";
/* ----------------------------------------接收------------------------------------------------------*/
/**
* 转换成bean 含有 BaseFrame
*
* @param bytes 字节流
* @param t 类
* @param frame 需要拷贝该类
* @param <T> 类
* @return T
*/
public <T> T toBeanFrame(byte[] bytes, Class<T> t, BaseFrame frame) {
return StructRecvUtil.toBean(bytes, t, frame, BaseFrame.FRAME_HEAD_LENGTH, true, false);
}
public <T> T toWinBeanFrame(byte[] bytes, Class<T> t, BaseFrame frame) {
return StructRecvUtil.toBean(bytes, t, frame, BaseFrame.FRAME_HEAD_LENGTH, true, true);
}
/**
* 转换成bean 从 0 开始
*
* @param bytes 字节流
* @param t 类
* @param <T> 类
* @return T
*/
public <T> T toBean(byte[] bytes, Class<T> t) {
return StructRecvUtil.toBean(bytes, t, null, 0, false, false);
}
public <T> T toBean(byte[] bytes, Class<T> t, int startLocation, boolean isWin) {
return StructRecvUtil.toBean(bytes, t, null, startLocation, startLocation > 0, isWin);
}
public <T> T toWinBean(byte[] bytes, Class<T> t) {
return StructRecvUtil.toBean(bytes, t, null, 0, false, true);
}
/**
* 反射 加载 被 @StructRecv 修饰的 T
* <p>赋值不包括 父类</p>
*
* @param bytes 字节流
* @param t 类
* @param frame 需要拷贝的 基础实体类
* @param startLocation 起始位置
* @param skipAnalysis 跳过baseFrame
* @param <T> 类
* @return T
*/
@SneakyThrows
private <T> T toBean(byte[] bytes, Class<T> t, BaseFrame frame, int startLocation, boolean skipAnalysis, boolean isWin) {
T entity = t.getDeclaredConstructor().newInstance();
if (ArrayUtil.isEmpty(bytes) || bytes.length <= BaseFrame.FRAME_HEAD_LENGTH) {
return entity;
}
Class<?> clazz = entity.getClass();
// 类 顺序接收
List<Class<?>> classList = new LinkedList<>();
classList.add(t);
// 得到 父类 所有需要解析的bean
StructRecvUtil.analysisSuperClass(clazz, skipAnalysis, classList);
// 当前类解析 包含子类 深层递归解析
if (!clazz.isAnnotationPresent(StructRecv.class)) {
return entity;
}
// 计算解析开始位置
AtomicInteger atomicInteger = new AtomicInteger(startLocation);
// 解析 并 递归子类
for (int i = classList.size() - 1; i >= 0; i--) {
StructRecvUtil.loadingReqField(bytes, classList.get(i), entity, atomicInteger, isWin);
}
// 是否拷贝 BaseFrame
if (frame != null) {
BeanUtil.copyProperties(frame, entity);
}
return entity;
}
/**
* 接收 深层 解析 父类
*
* @param clazz class
* @param skipAnalysis s跳过BaseFrame
* @param classList 类接收
*/
private void analysisSuperClass(Class<?> clazz, boolean skipAnalysis, List<Class<?>> classList) {
Class<?> superClass = clazz.getSuperclass();
String simpleName = superClass.getSimpleName();
// 如果 为 object 或者 Packet 最外层
boolean marginFlag = simpleName.equals(Object.class.getSimpleName()) || simpleName.equals(Packet.class.getSimpleName());
// 如果为 BaseFrame 并且 进行 BaseFrame 拷贝 则 不解析
boolean frameFlag = simpleName.equals(BaseFrame.class.getSimpleName()) && skipAnalysis;
if (marginFlag || frameFlag) {
return;
}
// 需要解析
classList.add(superClass);
// 否则 是 需要的
StructRecvUtil.analysisSuperClass(superClass, skipAnalysis, classList);
}
/**
* 赋值 请求 字段
*
* @param bytes 原数据
* @param entity 实体类
* @param startLocation 下一个位置(可能递归)
* @param <T> T
*/
@SneakyThrows
private <T> void loadingReqField(byte[] bytes, Class<?> clazz, T entity, AtomicInteger startLocation, boolean isWin) {
// 当前 类 的报文数组
int[] recvArray = clazz.getAnnotation(StructRecv.class).value();
// 下一个位置
AtomicInteger nextRecv = new AtomicInteger(0);
for (Field field : clazz.getDeclaredFields()) {
// 报文已经解析完毕
if (nextRecv.get() > recvArray.length - 1) {
return;
}
Object val;
if (field.isAnnotationPresent(StructRecvField.class)) {
// 特殊的 类型
StructRecvField recvField = field.getAnnotation(StructRecvField.class);
if (recvField.value() == RecvFieldTypeEnum.IGNORE) {
continue;
}
if (recvField.value() == RecvFieldTypeEnum.RECV_REVERSAL) {
// 反转
val = ByteUtil.toIntReverse(bytes, startLocation.get(), recvArray[nextRecv.get()]);
} else if (recvField.value() == RecvFieldTypeEnum.LIST_COUNT || recvField.value() == RecvFieldTypeEnum.LIST_LEN) {
// list 发送的
val = StructRecvUtil.getBasicTypeReq(bytes, startLocation, recvArray, nextRecv, isWin, field);
} else if (recvField.value() == RecvFieldTypeEnum.LIST) {
// list 接收的
List<Object> list = new ArrayList<>();
StructRecv recv = recvField.bean().getAnnotation(StructRecv.class);
// 得到 结构体的大小
int recvVal = Arrays.stream(recv.value()).sum();
// 获取 已经 解析的 list count 数量
int count;
if (NumberUtil.isNumber(recvField.count())) {
count = NumberUtil.parseInt(recvField.count());
} else {
Method method = entity.getClass().getMethod(StrUtil.upperFirstAndAddPre(recvField.count(), "get"));
count = NumberUtil.parseInt(String.valueOf(method.invoke(entity)));
}
for (int i = 0; i < count; i++) {
list.add(StructRecvUtil.toBean(bytes, recvField.bean()
, startLocation.getAndAdd(recvVal), isWin));
}
val = list;
} else if (recvField.value() == RecvFieldTypeEnum.IP) {
// 特殊格式处理 ip、mac
long ip = ByteUtil.toLong(bytes, startLocation.get(), recvArray[nextRecv.get()]);
val = NetUtil.longToIpv4(ip);
} else if (recvField.value() == RecvFieldTypeEnum.TIME_SYS) {
// 特殊的时间处理
val = ByteUtil.toTime(bytes, startLocation.get());
} else {
val = ByteUtil.toString(bytes, startLocation.get(), recvArray[nextRecv.get()]);
}
} else {
val = StructRecvUtil.getBasicTypeReq(bytes, startLocation, recvArray, nextRecv, isWin, field);
}
if (val instanceof String && String.valueOf(val).endsWith("�")) {
// 尾部 可能存在乱码情况
val = StrUtil.subAfter(String.valueOf(val), "�", false);
}
startLocation.getAndAdd(recvArray[nextRecv.getAndIncrement()]);
// 注入值
field.setAccessible(true);
field.set(entity, val);
}
}
/**
* 获取基础类型请求
*
* @param bytes 数据
* @param location 位置
* @param recvArray 结构体对应数组
* @param nextLocation 下一个位置
* @param isWin 是否为 window
* @param field 字段
* @return 数据
*/
@SneakyThrows
private Object getBasicTypeReq(byte[] bytes, AtomicInteger location, int[] recvArray
, AtomicInteger nextLocation, boolean isWin, Field field) {
Object val;
String type = field.getGenericType().toString().toLowerCase();
// 默认的属性支持
if (type.contains(HBX_TYPE)) {
Object obj = field.getType().getDeclaredConstructor().newInstance();
StructRecvUtil.loadingReqField(bytes, obj.getClass(), obj, location, isWin);
val = obj;
} else if (type.contains(DATE_TYPE)) {
long date = ByteUtil.toLong(bytes, location.get(), recvArray[nextLocation.get()]);
val = DateUtil.toLocalDateTime(DateUtil.date(date));
} else if (type.contains(INT_TYPE)) {
val = ByteUtil.toInt(bytes, location.get(), recvArray[nextLocation.get()]);
} else if (type.contains(LONG_TYPE)) {
val = ByteUtil.toLong(bytes, location.get(), recvArray[nextLocation.get()]);
} else {
if (isWin) {
val = ByteUtil.toStringGbk(bytes, location.get(), recvArray[nextLocation.get()]);
} else {
val = ByteUtil.toString(bytes, location.get(), recvArray[nextLocation.get()]);
}
}
return val;
}
/* ----------------------------------------响应------------------------------------------------------*/
public byte[] toBytes(Object data) {
return StructRecvUtil.toBytes(data, 0);
}
/**
* 转换成 bean 带有 BaseFrame
*
* @param data 数据
* @return byte[]
*/
public byte[] toBytesFrame(Object data) {
return StructRecvUtil.toBytes(data, BaseFrame.FRAME_HEAD_LENGTH);
}
/**
* 响应解析
*
* @param data 数据
* @param baseFrame BaseFrame 是否解析
* @return byte[]
*/
public byte[] toBytes(Object data, int baseFrame) {
if (data == null) {
return new byte[0];
}
Class<?> clazz = data.getClass();
if (!clazz.isAnnotationPresent(StructRecv.class)) {
log.error("错误的报文响应:\t{}", data.toString());
return new byte[0];
}
boolean frameAnalysis = baseFrame == BaseFrame.FRAME_HEAD_LENGTH;
List<Class<?>> classList = new LinkedList<>();
classList.add(data.getClass());
// 得到所有父类,并计算出 总长度
StructRecvUtil.analysisSuperClass(clazz, frameAnalysis, classList);
int len = baseFrame + classList.stream()
.mapToInt(e -> Arrays.stream(e.getAnnotation(StructRecv.class).value()).sum())
.sum();
// 计算内部类 单个 或 集合
len += StructRecvUtil.geInnerClassLength(clazz, data);
// 剔除 BaseFrame
classList.remove(BaseFrame.class);
// 计算长度
byte[] bytes = new byte[len];
BaseFrame frame = new BaseFrame();
BeanUtil.copyProperties(data, frame);
boolean isWin = ModuleTypeUtil.isWin(frame.getFrameNo());
// 是否需要 计算 BaseFrame
if (baseFrame == BaseFrame.FRAME_HEAD_LENGTH) {
// 设置中心响应
frame.setFrameNo(Integer.parseInt(ModuleTypeEnum.CENTER.getValue()));
frame.setFrameLength(len);
StructRecvUtil.loadingResField(frame, BaseFrame.class, bytes, new AtomicInteger(0), isWin);
}
AtomicInteger atomicInteger = new AtomicInteger(12);
// 因 需要 从 顶级 父类 往下面解析
for (int i = classList.size() - 1; i >= 0; i--) {
// 私有动态计算
StructRecvUtil.loadingResField(data, classList.get(i), bytes, atomicInteger, isWin);
}
return bytes;
}
/**
* 自动装载 私有 字段
*
* @param clazz 类
* @param bytes 数组
* @param nextLocation 下一个 报文
* @param isWind 是否为windows
*/
@SneakyThrows
private void loadingResField(Object data, Class<?> clazz, byte[] bytes, AtomicInteger nextLocation, boolean isWind) {
AtomicInteger recvLocation = new AtomicInteger(0);
int[] recvArray = clazz.getAnnotation(StructRecv.class).value();
for (Field field : clazz.getDeclaredFields()) {
// 报文已经解析完毕
if (recvLocation.get() > recvArray.length - 1) {
return;
}
// 忽略的
StructRecvField recvField = field.getAnnotation(StructRecvField.class);
if (recvField != null && recvField.value() == RecvFieldTypeEnum.IGNORE) {
continue;
}
Method method = clazz.getMethod(StrUtil.upperFirstAndAddPre(field.getName(), "get"));
Object result = method.invoke(data);
if (field.isAnnotationPresent(StructRecvField.class) && recvField != null
&& recvField.value() != RecvFieldTypeEnum.RECV_REVERSAL) {
if (recvField.value() == RecvFieldTypeEnum.SIZE) {
// 规则 发送 时 策略总大小,不包含 BaseFrame
Class<?> aClass = data.getClass();
int local = Arrays.stream(aClass.getAnnotation(StructRecv.class).value()).sum();
int length = StructRecvUtil.geInnerClassLength(aClass, data);
// 只继承一层父类
int parent = Arrays.stream(aClass.getSuperclass().getAnnotation(StructRecv.class).value()).sum();
ByteUtil.toBytes(local + length + parent, bytes, nextLocation.get(), recvArray[recvLocation.get()]);
} else if (recvField.value() == RecvFieldTypeEnum.SIZE_POLICY) {
// 规则 发送时 单纯 策略大小
Class<?> aClass = data.getClass();
// 本地的
int local = Arrays.stream(aClass.getAnnotation(StructRecv.class).value()).sum();
int length = StructRecvUtil.geInnerClassLength(aClass, data);
ByteUtil.toBytes(local + length, bytes, nextLocation.get(), recvArray[recvLocation.get()]);
} else if (recvField.value() == RecvFieldTypeEnum.IP) {
ByteUtil.toBytes(NetUtil.ipv4ToLong(String.valueOf(result))
, bytes, nextLocation.get(), recvArray[recvLocation.get()]);
} else if (recvField.value() == RecvFieldTypeEnum.LIST_COUNT) {
// 解析出 list 的 count
method = clazz.getMethod(StrUtil.upperFirstAndAddPre(recvField.field(), "get"));
int size = ((List) method.invoke(data)).size();
//进程策略特殊处理
if (clazz.getSimpleName().equals(PolicyConstant.PROCESS_POLICY) && size > 1) {
size -= 1;
}
ByteUtil.toBytes(size, bytes, nextLocation.get(), recvArray[recvLocation.get()]);
} else if (recvField.value() == RecvFieldTypeEnum.LIST_LEN) {
method = clazz.getMethod(StrUtil.upperFirstAndAddPre(recvField.field(), "get"));
int count = ((List) method.invoke(data)).size();
StructRecv recv = recvField.bean().getAnnotation(StructRecv.class);
// 得到 结构体的大小
int recvVal = Arrays.stream(recv.value()).sum();
ByteUtil.toBytes(count * recvVal, bytes, nextLocation.get(), recvArray[recvLocation.get()]);
} else if (recvField.value() == RecvFieldTypeEnum.LIST) {
// list 数据 动态计算出大小 --- 存放于最后一位
for (Object obj : (List) result) {
// 注意: 内部类不能继承父类
StructRecvUtil.loadingResField(obj, obj.getClass(), bytes, nextLocation, isWind);
}
}
} else if (result != null) {
// 判断是否有子类
String type = field.getType().toString().toLowerCase();
if (type.contains(HBX_TYPE)) {
StructRecvUtil.loadingResField(data, clazz, bytes, nextLocation, isWind);
continue;
}
// 赋值 计算出 下一个位置
if (type.contains(STRING_TYPE)) {
if (isWind) {
ByteUtil.toBytesGbk(String.valueOf(result), bytes, nextLocation.get());
} else {
ByteUtil.toBytes(String.valueOf(result), bytes, nextLocation.get());
}
} else if (type.contains(DATE_TYPE)) {
LocalDateTime time = (LocalDateTime) result;
ByteUtil.toBytes(Timestamp.valueOf(time).getTime()
, bytes, nextLocation.get(), recvArray[recvLocation.get()]);
} else {
ByteUtil.toBytes(NumberUtil.parseLong(String.valueOf(result)), bytes
, nextLocation.get(), recvArray[recvLocation.get()]);
}
}
// 更新坐标
nextLocation.getAndAdd(recvArray[recvLocation.getAndIncrement()]);
}
}
/**
* 获取 子类
*
* @param clazz 类
* @param data 数据
* @return Integer
*/
private int geInnerClassLength(Class<?> clazz, Object data) {
int len = 0;
StructRecv annotation = clazz.getAnnotation(StructRecv.class);
if (annotation.hasInnerClass()) {
for (Field field : clazz.getDeclaredFields()) {
// 单个类
String packagePath = field.getType().toString().toLowerCase();
if (packagePath.contains(HBX_TYPE)) {
StructRecv structRecv = field.getClass().getAnnotation(StructRecv.class);
len += Arrays.stream(structRecv.value()).sum();
continue;
}
// 集合类
if (field.isAnnotationPresent(StructRecvField.class)) {
StructRecvField recvField = field.getAnnotation(StructRecvField.class);
if (recvField.value() == RecvFieldTypeEnum.LIST) {
try {
Method method = clazz.getMethod(StrUtil.upperFirstAndAddPre(field.getName(), "get"));
List list = (List) method.invoke(data);
StructRecv recv = recvField.bean().getAnnotation(StructRecv.class);
int count = Arrays.stream(recv.value()).sum();
len += (list.size() * count);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
}
return len;
}
}
四、使用
使用@StructRecv() 标注字节数,注意对应顺序
import com.hbcloud.hbx.audit.centre.common.annotaion.StructRecv;
import com.hbcloud.hbx.audit.centre.common.entity.BaseFrame;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 中心确认信息
*
* @author wbw
* @date 2020/8/2 10:13
*/
@EqualsAndHashCode(callSuper = true)
@Data
@StructRecv({4, 4, 64, 128, 128, 8, 8})
public class CenterConfirmInfo extends BaseFrame {
/**
* 大小
*/
private Integer size;
/**
* 客户端确认状态 0.未确认 1.确认
*/
private Integer sign;
/**
* 主机名称
*/
private String hostName;
/**
* 客户端的责任人名称
*/
private String onwerName;
/**
* 客户端的部门名称
*/
private String deptName;
/**
* 客户端的机构ID
*/
private Integer deptId;
/**
* 客户端的用户ID
*/
private Long userId;
/**
* 客户端的用户名称
*/
private String userName;
}
具体方法使用
// 解析成实体类
CenterConfirmInfo info = StructRecvUtil.toBean(new byte[数据懒得写,省略了;],CenterConfirmInfo.class);
// 解析成 字节 byte
byte[] bytes = StructRecvUtil.toBytes(info);
五、结束
这里面并没有什么复杂的地方,本质上就是对解析的这一步骤进行数据抽象与封装。