我开始将自定义序列化机制迁移到Protocol Buffers。一种特别定期使用的数据类型是BigDecimal
。
有没有人知道在Protocol Buffers中序列化这个的好方法?我们当前的序列化例程使用BigDecimal.toPlainString()
进行序列化,使用new BigDecimal(String)
进行反序列化 - 我假设有更好的方法。
我的猜测是将BigDecimal
定义为:
message BDecimal {
required int32 scale = 1;
required BInteger int_val = 2;
}
但我不太清楚如何定义BigInteger
- 也许使用其toByteArray()
方法?
答案 0 :(得分:14)
是。您应该将BigInteger定义为BigInteger.toByteArray()。
我的猜测是BigDecimal会:
message BDecimal {
required int32 scale = 1;
required BInteger int_val = 2;
}
而BigInteger可以定义为
message BInteger {
required bytes value = 1;
}
处理BigInteger的代码是:
BInteger write(BigInteger val) {
BInteger.Builder builder = BInteger.newBuilder();
ByteString bytes = ByteString.copyFrom(val.toByteArray());
builder.setValue(bytes);
return builder.build();
}
BigInteger read(BInteger message) {
ByteString bytes = message.getValue();
return new BigInteger(bytes.toByteArray());
}
答案 1 :(得分:0)
你为什么要改变它?仅仅因为你可以或者有真正的需要(比如分析会话确认,序列化/反序列化大部分时间都是这样)。
我会使用一个字符串,因为它是内置的:)
如果字符串表示似乎是一个问题,那么建议的字节数组方法(What is the best approach for serializing BigDecimal/BigInteger to ProtocolBuffers)对我来说似乎很好。
答案 2 :(得分:0)
我最近与OP具有相同的需求,并使用了与@notnoop提出的解决方案类似的解决方案。在看到来自@stikkos的评论后,将其发布到此处:
如何将BigDecimal转换为BigInteger并缩放?然后回来吗?
根据BigDecimal
类documentation:
BigDecimal
的值为(unscaledVal
× 10-scale
),根据精度和舍入模式设置进行舍入。
因此,可以考虑以下三个属性来对java.math.BigDecimal
进行序列化:
unscaledValue
scale
precision
现在,代码。
Protobuf v3消息定义:
syntax = "proto3";
message DecimalValue {
uint32 scale = 1;
uint32 precision = 2;
bytes value = 3;
}
如何将java.math.BigDecimal
序列化为Protobuf消息:
import com.google.protobuf.ByteString;
import DecimalValue;
java.math.BigDecimal bigDecimal = new java.math.BigDecimal("1234.56789");
DecimalValue serialized = DecimalValue.newBuilder()
.setScale(bigDecimal.scale())
.setPrecision(bigDecimal.precision())
.setValue(ByteString.copyFrom(bigDecimal.unscaledValue().toByteArray()))
.build();
如何将Protobuf消息反序列化回java.math.BigDecimal
:
java.math.MathContext mc = new java.math.MathContext(serialized.getPrecision());
java.math.BigDecimal deserialized = new java.math.BigDecimal(
new java.math.BigInteger(serialized.getValue().toByteArray()),
serialized.getScale(),
mc);
我们可以检查获得的java.math.BigDecimal
产生的原始值如下:
assert bigDecimal.equals(deserialized);
注意:OP认为序列化java.math.BigDecimal
的方法比使用普通String
更好。在存储方面,此解决方案更好。
例如,要序列化π的前100个小数:
3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679
System.out.println("DecimalValue: " + serialized.getSerializedSize());
System.out.println("String: " + StringValue.of(pi).getSerializedSize());
这将产生:
DecimalValue: 48
String: 104