将BigDecimal / BigInteger序列化为ProtocolBuffers的最佳方法是什么?

时间:2009-06-26 23:49:29

标签: java protocol-buffers

我开始将自定义序列化机制迁移到Protocol Buffers。一种特别定期使用的数据类型是BigDecimal

有没有人知道在Protocol Buffers中序列化这个的好方法?我们当前的序列化例程使用BigDecimal.toPlainString()进行序列化,使用new BigDecimal(String)进行反序列化 - 我假设有更好的方法。

我的猜测是将BigDecimal定义为:

message BDecimal {
    required int32 scale = 1;
    required BInteger int_val = 2;
}

但我不太清楚如何定义BigInteger - 也许使用其toByteArray()方法?

3 个答案:

答案 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并缩放?然后回来吗?

根据BigDecimaldocumentation

BigDecimal的值为(unscaledVal× 10-scale ),根据精度和舍入模式设置进行舍入。

因此,可以考虑以下三个属性来对java.math.BigDecimal进行序列化:


现在,代码。

  1. Protobuf v3消息定义:

    syntax = "proto3";
    
    message DecimalValue {
      uint32 scale = 1;
      uint32 precision = 2;
      bytes value = 3;
    }
    
  2. 如何将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();
    
  3. 如何将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);
    
  4. 我们可以检查获得的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