我该如何将ByteBuffer转换为Avro字节?

7
我有一个包含以下内容的Avro模式,作为其中一个字段。
{
  "name" : "currency",
  "type" : ["null","bytes"],
  "logicalType": "decimal",
  "precision": 9,
  "scale": 4
},

我运行了avro-tools jar文件来创建表示模式的Java文件。这将生成以下属性:public java.nio.ByteBuffer currency; 在我的代码的其他位置,我将使用BigDecimal类型的货币值。
当我创建此类的实例时,如何将BigDecimal值转换为预期的ByteBuffer?我可以直接使用ByteBuffer.toByteArray()吗?还是需要做一些特殊的处理以确保它与avro(以及其他可能读取数据的工具,如Impala)兼容?
1个回答

7
让我们先免责声明。虽然"逻辑类型"部分在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());
}

您可以阅读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似乎也能够生成预期的模式(但据我所知,尚未为逻辑类型创建专用注释)。
但是,我不清楚avro-compiler / codegen是否已更新以支持逻辑类型。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接