10. ProtoStuff不支持BigDecimal序列化/反序列化记录
约 667 字大约 2 分钟
平时使用ProtoStuff作为序列化工具,对于一些POJO对象序列化,但是在实际使用中,发现针对BigDecimal对象进行序列化时却出现了问题
- 不管什么数,生成的byte数组都一样
- 无法正确反序列化
下面记录一下这个问题
1. 场景复现
我们使用的protostuff依赖如下
<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,如下
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的场景
@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进行特殊处理
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");
}
}
再次测试,正常执行
Loading...