ProtoStuff不支持BigDecimal序列化/反序列化?

平时使用ProtoStuff作为序列化工具,对于一些POJO对象序列化,但是在实际使用中,发现针对BigDecimal对象进行序列化时却出现了问题

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

下面记录一下这个问题

1. 场景复现

我们使用的protostuff依赖如下

     com.dyuproject.protostuff    protostuff-core    1.1.3    com.dyuproject.protostuff    protostuff-runtime    1.1.3

写一个简单测试demo,如下

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 deserialize(byte[] paramArrayOfByte, Class targetClass) {    if (paramArrayOfByte != null && paramArrayOfByte.length != 0) {        Schema schema = RuntimeSchema.getSchema(targetClass);        T instance = schema.newMessage();        ProtostuffIOUtil.mergeFrom(paramArrayOfByte, instance, schema);        return instance;    } else {        throw new RuntimeException("Failed to deserialize");    }}@Testpublic 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: 其中回复为

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

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

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

@Datapublic static class InnerDecimal {    private BigDecimal decimal;    public InnerDecimal() {    }    public InnerDecimal(BigDecimal decimal) {        this.decimal = decimal;    }}@Testpublic 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进行特殊处理

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 deserialize(byte[] paramArrayOfByte, Class 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");    }}

再次测试,正常执行

发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章