java TLV高效序列化工具

TLV 序列化在Java中的应用:用于缓存和消息传递

TLV(Tag-Length-Value)序列化在Java应用程序通信、Redis缓存和消息队列等多种场景中起着关键作用。本文介绍如何使用tlv库的0.0.1版本实现TLV序列化。

github地址

在Maven的pom.xml中添加以下依赖:

<dependency>
    <groupId>com.github.fashionbrot</groupId>
    <artifactId>tlv</artifactId>
    <version>0.0.1</version>
</dependency>

在Gradle项目的build.gradle中添加以下依赖:

implementation 'com.github.fashionbrot:tlv:0.0.1'

支持类型如下,其他类型待实现

Integer.class,int.class
byte.class,Byte.class
boolean.class,Boolean.class
char.class,Character.class
short.class,Short.class
float.class,Float.class
long.class,Long.class
String.class,CharSequence.class
double.class,Double.class
BigDecimal.class
Date.class
LocalTime.class
LocalDate.class
LocalDateTime.class
List<XXX>
数组[XXX]

您可以为Java类中的字段添加注解以自定义序列化行为:

@Documented
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface TLVField {
    /**
     * 序号 从 1~N
     * @return 序号
     */
    int index() default Integer.MAX_VALUE;

    /**
     * 是否序列化
     * @return boolean
     */
    boolean serialize() default true;
}

TLV 结构概述

TLV结构如下所示:
TLV
T
L
V
占用1个字节
通过Varint 压缩 value长度
value
占用5bit
占用3bit
3个bit可以有8种组合代表长度1到8 代表L本身长度
T中后3个bit

示例Java类

考虑以下Java类 Test1Entity:
@Data
public class Test1Entity {
    private int a1;
    private String s1;
}
Test1Entity entity=new Test1Entity();
entity.setA1(12);
entity.setS1("你好");

# A1 序列化后 =  32, 1, 12
# 第一个字节32
# 32对应的bit = 00100000 
# 前5个bit = 00100 代表的类型=Integer
# 后3个bit = 000 代表的长度= 1 代表L的长度=1
# 按照000 = 1个长度,则往后取一个字节则=1,1代表value 长度
# 按照L 往后取1位 value = 12

#S1 序列化后 = 64, 6, -28, -67, -96, -27, -91, -67
# 64 对应的bit = 0100 0000 
# 01000 对应的类型=String
# 000 代表L的长度是1位
# 按照000=1 ,则取64后面1位字节则=66代表value 长度
# -28, -67, -96, -27, -91, -67  == 你好

示例1

    public void entityTest(){

        Test1Entity entity=new Test1Entity();
        entity.setA1(12);
        entity.setS1("你好");

        byte[] serialize = TLVUtil.serialize(entity);
        System.out.println(serialize.length);
        System.out.println(Arrays.toString(serialize));

        byte[] expected = new byte[]{32, 1, 12, 64, 6, -28, -67, -96, -27, -91, -67};

        Assert.assertTrue("Entity序列化失败",Arrays.equals(expected,serialize));

        Test1Entity deserialize = TLVUtil.deserialize(Test1Entity.class, serialize);
        System.out.println(deserialize.toString());
        Assert.assertEquals("基本类型反序列化失败",entity.toString(),deserialize.toString());
    }

示例2 支持注解方式

    @Data
    public static class TLVEntity{
        @TLVField(index = 1,serialize = false)
        private int c1;

        private String b1;

        @TLVField(index = 2,serialize = false)
        private String a1;

    }

    @Test
    public void test(){

        TLVEntity tlvEntity=new TLVEntity();
        tlvEntity.setA1("1");
        tlvEntity.setB1("2");
        tlvEntity.setC1(3);

        byte[] serialize = TLVUtil.serialize(tlvEntity);
        System.out.println(Arrays.toString(serialize));

        TLVEntity deserialize = TLVUtil.deserialize(TLVEntity.class, serialize);
        System.out.println(deserialize);

        Assert.assertTrue(deserialize.getA1()==null);
        Assert.assertTrue(deserialize.getB1().equals("2"));
        Assert.assertTrue(deserialize.getC1()==0);

    }

示例3

public class TLVSerializeTest {

    @Test
    public void test9(){

        Test2ChildEntity childEntity=new Test2ChildEntity();
        childEntity.setL1(1L);

        Test2ChildEntity childEntity2=new Test2ChildEntity();
        childEntity2.setL1(2L);

        Test2Entity entity=new Test2Entity();
        entity.setArray(new Test2ChildEntity[]{childEntity2,childEntity});
        entity.setList(Arrays.asList(childEntity,childEntity2));


        PageResponse pageResponse=new PageResponse();
        pageResponse.setRows(Arrays.asList(entity));
        pageResponse.setTotal(1);


        Response response=new Response();
        response.setData(pageResponse);
        response.setCode(0);
        response.setMsg("成功");


        byte[] bytes = TLVUtil.serialize(response);
        System.out.println(Arrays.toString(bytes));
        System.out.println(bytes.length);

        Response deserialize = TLVUtil.deserialize(Response.class, bytes);
        String jsonString = JSON.toJSONString(deserialize);
        System.out.println(jsonString);
        System.out.println(jsonString.getBytes().length);
        Assert.assertTrue(Objects.equals(response,deserialize));
    }

}



  • 15
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个基本的TLV拼接工具类,用Java实现: ```java import java.util.ArrayList; import java.util.List; public class TLVUtils { /** * TLV编码 * @param tag 标签 * @param value 值 * @return TLV编码后的字节数组 */ public static byte[] encode(int tag, byte[] value) { int len = value.length; if (len > 127) { // 如果长度超过127,需要使用多字节表示长度 int byteNum = 1; int tempLen = len; while (tempLen > 0) { tempLen >>= 8; byteNum++; } byte[] lenBytes = new byte[byteNum]; lenBytes[0] = (byte) (0x80 | byteNum - 1); for (int i = 1; i < byteNum; i++) { lenBytes[byteNum - i] = (byte) (len & 0xFF); len >>= 8; } byte[] tlv = new byte[1 + byteNum + len]; tlv[0] = (byte) tag; System.arraycopy(lenBytes, 0, tlv, 1, byteNum); System.arraycopy(value, 0, tlv, 1 + byteNum, len); return tlv; } else { // 如果长度在0-127之间,直接使用1字节表示长度 byte[] tlv = new byte[1 + 1 + len]; tlv[0] = (byte) tag; tlv[1] = (byte) len; System.arraycopy(value, 0, tlv, 1 + 1, len); return tlv; } } /** * TLV解码 * @param data TLV编码后的字节数组 * @return List<TLV>对象 */ public static List<TLV> decode(byte[] data) { List<TLV> tlvList = new ArrayList<>(); int pos = 0; while (pos < data.length) { int tag = data[pos] & 0xFF; pos++; int len = data[pos] & 0xFF; pos++; if ((len & 0x80) != 0) { // 如果长度字节的最高位是1,表示后面跟着的是多字节长度 len &= 0x7F; for (int i = 0; i < len; i++) { len <<= 8; len |= data[pos] & 0xFF; pos++; } } byte[] value = new byte[len]; System.arraycopy(data, pos, value, 0, len); pos += len; TLV tlv = new TLV(tag, value); tlvList.add(tlv); } return tlvList; } /** * TLV对象 */ public static class TLV { private int tag; private byte[] value; public TLV(int tag, byte[] value) { this.tag = tag; this.value = value; } public int getTag() { return tag; } public byte[] getValue() { return value; } @Override public String toString() { return "TLV{" + "tag=" + tag + ", value=" + bytesToHexString(value) + '}'; } } /** * 将字节数组转换为十六进制字符串 * @param bytes 字节数组 * @return 十六进制字符串 */ public static String bytesToHexString(byte[] bytes) { StringBuilder sb = new StringBuilder(); for (byte b : bytes) { sb.append(String.format("%02X", b)); } return sb.toString(); } } ``` 使用示例: ```java public class Test { public static void main(String[] args) { byte[] data = TLVUtils.encode(0x01, new byte[]{0x01, 0x02, 0x03}); System.out.println(TLVUtils.bytesToHexString(data)); List<TLVUtils.TLV> tlvList = TLVUtils.decode(data); for (TLVUtils.TLV tlv : tlvList) { System.out.println(tlv.toString()); } } } ``` 输出结果: ``` 0103010203 TLV{tag=1, value=010203} ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值