如何从ByteBuffer转换为Avro字节?

dav*_*dev 5 java avro

我有一个avro模式,其中包括以下内容作为字段之一

{
  "name" : "currency",
  "type" : ["null","bytes"],
  "logicalType": "decimal",
  "precision": 9,
  "scale": 4
},
Run Code Online (Sandbox Code Playgroud)

我运行了avro-tools jar来创建表示模式的java文件。产生的属性如下所示:public java.nio.ByteBuffer currency;

在代码的其他地方,我将使用BigDecimal类型中的货币值。

创建此类的实例时,如何将BigDecimal值转换为期望值ByteBuffer?我可以只使用ByteBuffer.toByteArray()还是我需要做一些特别的事情以确保它与avro(以及可能正在读取数据的其他工具,例如Impala)兼容?

Clé*_*IEU 6

让我们从免责声明开始。尽管大约在2014年的规范中出现了“逻辑类型”部分,但任何Avro Java版本均不支持该部分。

您可以决定声明一个符合规范的架构,然后将正确的字节放入字段中,但是Avro Java不会帮您(就像您省略了与逻辑类型相关的字段一样)。

如何将BigDecimal值转换为预期的ByteBuffer

该文档指出:

十进制逻辑类型注释Avro字节或固定类型。字节数组必须包含二进制补码表示的的未缩放的整数值大端字节顺序。比例尺是固定的,并使用属性指定。

可以将其翻译成Java(复制自Avro 1.8.0-rc2):

public ByteBuffer toBytes(BigDecimal value, Schema schema, LogicalType type)
{
    int scale = ((LogicalTypes.Decimal) type).getScale();
    if (scale != value.scale()) {
        throw new AvroTypeException("Cannot encode decimal with scale " +
          value.scale() + " as scale " + scale);
    }

    return ByteBuffer.wrap(value.unscaledValue().toByteArray());
}
Run Code Online (Sandbox Code Playgroud)

您可以阅读BigDecimal和BigInteger的Javadoc来检查value.unscaledValue().toByteArray()是否符合规范。

以类似的方式,您可以使用以下代码反序列化字段: return new BigDecimal(new BigInteger(bytes), scale);

您应该使用逻辑类型吗?

如序言中所述,如果您使用的是Avro 1.7,则免费提供免费软件。您必须编写自己的(反)序列化器,代码生成和反映不支持此构造。使用它的唯一原因是遵守规范,并希望将来的Avro版本将使您的生活更轻松。

Avro 1.8.0-rc2包含一些代码以支持逻辑类型并引入新的逻辑类型。似乎为所有逻辑类型(请参见ConversionConversions)提供了(反)序列化器,并且转换已插入GenericData中。这意味着BigDecimal当您询问字段值时,您将收到一个实例。如果正确注释字段,则ReflectData似乎也可以产生预期的模式(但是AFAIK尚未为逻辑类型创建专用注释)。

但是,我不清楚avro-compiler / codegen是否已更新为支持逻辑类型。