一緒に創造し、成長するために一緒に働きましょう!「ナゲッツデイリー新プラン・8月アップデートチャレンジ」参加12日目、イベント詳細はこちら
普段は ProtoStuff をシリアライズツールとして使って POJO オブジェクトをシリアライズしているのですが、実際に使ってみると BigDecimal オブジェクトをシリアライズする際に問題があることがわかりました
- 数に関係なく、結果のバイト配列は同じです
- 正しくデシリアライズできない
この問題を以下に記録します
1.シーン再現
私たちが使用するプロトスタッフの依存関係は次のとおりです
<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>
复制代码
次のように、簡単なテスト デモを作成します。
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 に問題があります: github.com/protostuff/…。返信は次のとおりです。
Protostuff は、組み込みの jdk 型ではなく、ユーザー定義型 (pojos) で動作します。
上記のステートメントは、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");
}
}
复制代码
再テスト、通常実行
声明
信仰の手紙のようなものではありません.内容はすでに書かれており、純粋に家族からのものです.個人の能力が限られているため、省略や間違いがあることは避けられません.バグを見つけた場合やより良い提案があれば、それらを批判して修正することを歓迎します。
- QQ: グレーグレー / 3302797840
- 公開番号: 灰色のブログ
- 灰色のサイト: hhui.top