ProtoStuff不支持BigDecimal序列化及反序列化詳解

引言

平時使用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: github.com/protostuff/…,其中回復為

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");
    }
}

再次測試,正常執行

以上就是ProtoStuff不支持BigDecimal序列化及反序列化詳解的詳細內容,更多關於ProtoStuff不支持BigDecimal的資料請關註WalkonNet其它相關文章!

推薦閱讀: