2016-01-19 10 views
4

У меня есть Avro схема, которая включает в себя следующее в качестве одного из полеяКак конвертировать из ByteBuffer в Avro байты?

{ 
    "name" : "currency", 
    "type" : ["null","bytes"], 
    "logicalType": "decimal", 
    "precision": 9, 
    "scale": 4 
}, 

Я побежал Avro-инструменты банки, чтобы создать файл Java для представления схемы. Это создало свойство, которое выглядит следующим образом: public java.nio.ByteBuffer currency;

В другом месте моего кода я буду работать с валютными значениями в BigDecimal типах.

Как преобразовать значение BigDecimal в ожидаемое значение ByteBuffer при создании экземпляра этого класса? Могу я просто использовать ByteBuffer.toByteArray() или мне нужно сделать что-нибудь особенное, чтобы обеспечить его совместимость с avro (и другими инструментами, такими как Impala, которые могут читать данные)?

ответ

4

Начнем с отказа от ответственности. Хотя раздел «Логические типы» появился в спецификации около 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()); 
} 

Вы можете читать Javadoc BigDecimal & BigInteger, чтобы проверить, что value.unscaledValue().toByteArray() соответствует спецификации.

Подобным же образом, вы можете десериализации поле, используя следующий код: return new BigDecimal(new BigInteger(bytes), scale);

Если вы используете логические типы?

Как сказано в преамбуле, если вы используете Avro 1.7, то ничего не получится бесплатно. Вы должны написать свой собственный (де) сериализатор, генерация кода & отражать не поддерживают эту конструкцию. Единственная причина для его использования - соблюдать спецификацию и надеяться, что будущие выпуски Avro облегчат вашу жизнь.

Avro 1.8.0-rc2 содержит код для поддержки логических типов и представления новых логических типов. Похоже, что сериализаторы (de) предоставляются для всех логических типов (см. Conversion и Conversions) и что преобразования были подключены к GenericData. Это означает, что вы получите экземпляр BigDecimal, когда задаете значение поля. ReflectData, похоже, также может создавать ожидаемую схему, если вы правильно аннотируете это поле (но AFAIK не выделяет выделенных аннотаций для логических типов).

Однако мне непонятно, был ли обновлен avro-компилятор/codegen для поддержки логических типов.

Смежные вопросы