如何从ByteBuffer转换为Avro字节?

时间:2016-01-19 00:55:32

标签: java avro

我有一个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 个答案:

答案 0 :(得分:4)

让我们从免责声明开始。虽然"逻辑类型"部分出现在大约2014年的规范中,任何Avro Java版本都不支持它。

您可以决定声明符合规范的模式并将正确的字节推送到字段中,但Avro Java不会帮助您(就像您省略了逻辑类型相关字段一样)。

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

文档说明:

  

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

可以用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,则不会免费提供任何内容。你必须编写自己的(de)序列化器,代码生成和反映不支持这种结构。使用它的唯一原因是遵守规范,并希望未来的Avro版本能让您的生活更轻松。

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

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