190920-ProtoStuff不支持BigDecimal序列化/反序列化记录

文章目录
  1. 1. 场景复现
  2. 2. 疑似原因与兼容方法
  • II. 其他
    1. 1. 一灰灰Blog: https://liuyueyi.github.io/hexblog
    2. 2. 声明
    3. 3. 扫描关注
  • 平时使用ProtoStuff作为序列化工具,对于一些POJO对象序列化,但是在实际使用中,发现针对BigDecimal对象进行序列化时却出现了问题

    • 不管什么数,生成的byte数组都一样
    • 无法正确反序列化

    下面记录一下这个问题

    1. 场景复现

    我们使用的protostuff依赖如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     <dependency>
    <groupId>com.dyuproject.protostuff</groupId>
    <artifactId>protostuff-core</artifactId>
    <version>1.1.3</version>
    </dependency>
    <dependency>
    <groupId>com.dyuproject.protostuff</groupId>
    <artifactId>protostuff-runtime</artifactId>
    <version>1.1.3</version>
    </dependency>

    写一个简单测试demo,如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    public static byte[] serialize(Object obj) {
    Schema schema = RuntimeSchema.getSchema(obj.getClass());
    LinkedBuffer buffer = LinkedBuffer.allocate(1048576);

    byte[] protoStuff;
    try {
    protoStuff = ProtostuffIOUtil.toByteArray(obj, schema, buffer);
    } catch (Exception var8) {
    throw new RuntimeException("Failed to serializer");
    } finally {
    buffer.clear();
    }

    return protoStuff;
    }

    public static <T> T deserialize(byte[] paramArrayOfByte, Class<T> targetClass) {
    if (paramArrayOfByte != null && paramArrayOfByte.length != 0) {
    Schema<T> schema = RuntimeSchema.getSchema(targetClass);
    T instance = schema.newMessage();
    ProtostuffIOUtil.mergeFrom(paramArrayOfByte, instance, schema);
    return instance;
    } else {
    throw new RuntimeException("Failed to deserialize");
    }
    }


    @Test
    public void testSer() {
    byte[] ans = serialize(new BigDecimal(20));
    byte[] ans2 = serialize(new BigDecimal(120));

    System.out.println(new String(ans));
    System.out.println(new String(ans2));

    BigDecimal res = deserialize(ans, BigDecimal.class);
    System.out.println(res);
    }

    执行如下

    2. 疑似原因与兼容方法

    并没有找到具体的原因,在github上有一个issure: https://github.com/protostuff/protostuff/issues/245,其中回复为

    Protostuff works on user-defined types (pojos), not on built-in jdk types.

    上面的说法是ProtoStuff更多的是用于简单对象的序列化,而不是基础的jdk类型,因此推荐的是序列一个成员变量为BigDecimal的对象

    接下来我们试一下,定义一个简单的对象,成员为BigDecimal的场景

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    @Data
    public static class InnerDecimal {
    private BigDecimal decimal;

    public InnerDecimal() {
    }

    public InnerDecimal(BigDecimal decimal) {
    this.decimal = decimal;
    }
    }

    @Test
    public void testSer() {
    byte[] ans = serialize(new InnerDecimal(new BigDecimal(20.123)));
    byte[] ans2 = serialize(new InnerDecimal(new BigDecimal(120.1970824)));

    System.out.println(new String(ans));
    System.out.println(new String(ans2));

    InnerDecimal res = deserialize(ans, InnerDecimal.class);
    System.out.println(res);
    }

    测试输出如下

    上面虽然可以正常工作,但与我们希望的差别有点大,序列化一个BigDecimal,还需要定义一个POJO包装他,有点麻烦;于是一个猥琐的方法就是在序列化和反序列化的时候,针对BigDeimal进行特殊处理

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    public static byte[] serialize(Object obj) {
    if (obj instanceof BigDecimal) {
    obj = ((BigDecimal) obj).toPlainString();
    }

    Schema schema = RuntimeSchema.getSchema(obj.getClass());
    LinkedBuffer buffer = LinkedBuffer.allocate(1048576);

    byte[] protoStuff;
    try {
    protoStuff = ProtostuffIOUtil.toByteArray(obj, schema, buffer);
    } catch (Exception var8) {
    throw new RuntimeException("Failed to serializer");
    } finally {
    buffer.clear();
    }

    return protoStuff;
    }

    public static <T> T deserialize(byte[] paramArrayOfByte, Class<T> targetClass) {
    if (paramArrayOfByte != null && paramArrayOfByte.length != 0) {
    Schema schema;
    if (targetClass.isAssignableFrom(BigDecimal.class)) {
    schema = RuntimeSchema.getSchema(String.class);
    Object instance = schema.newMessage();
    ProtostuffIOUtil.mergeFrom(paramArrayOfByte, instance, schema);
    return (T) new BigDecimal((String) instance);
    } else {
    schema = RuntimeSchema.getSchema(targetClass);
    Object instance = schema.newMessage();
    ProtostuffIOUtil.mergeFrom(paramArrayOfByte, instance, schema);
    return (T) instance;
    }
    } else {
    throw new RuntimeException("Failed to deserialize");
    }
    }

    再次测试,正常执行

    II. 其他

    1. 一灰灰Bloghttps://liuyueyi.github.io/hexblog

    一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛

    2. 声明

    尽信书则不如,已上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激

    3. 扫描关注

    一灰灰blog

    QrCode

    知识星球

    goals

    评论

    Your browser is out-of-date!

    Update your browser to view this website correctly. Update my browser now

    ×