平时使用ProtoStuff作为序列化工具,对于一些POJO对象序列化,但是在实际使用中,发现针对BigDecimal对象进行序列化时却出现了问题
- 不管什么数,生成的byte数组都一样
- 无法正确反序列化
下面记录一下这个问题
1. 场景复现
我们使用的protostuff依赖如下
| 12
 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,如下
| 12
 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的场景
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 
 | @Datapublic 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进行特殊处理
| 12
 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. 其他
一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛
2. 声明
尽信书则不如,已上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激
3. 扫描关注
一灰灰blog

知识星球
