Полиморфизм и наследование в схемах Авро

Можно ли написать схему Avro/IDL, которая будет генерировать Java-класс, который либо расширяет базовый класс, либо реализует интерфейс? Кажется, что сгенерированный класс Java расширяет org.apache.avro.specific.SpecificRecordBase. Таким образом, орудия могут быть путем. Но я не знаю, возможно ли это.

Я видел примеры с предложениями по определению явного поля типа в каждой конкретной схеме с большей ассоциацией, чем семантикой наследования.

Я использую свой базовый класс в моих классах factory и других частях кода с помощью дженериков типа <T extends BaseObject>. В настоящее время у меня был код, созданный с помощью схемы JSON, которая поддерживает наследование.

Другой вопрос: можете ли вы использовать IDL для определения только записей без определения протокола? Я думаю, что ответ отрицательный, потому что компилятор жалуется на недостающее ключевое слово протокола.

Помогите оценить! Спасибо.

Ответы

Ответ 1

Я нашел лучший способ решить эту проблему. Глядя на источник генерации схемы в Avro, я понял, что внутри логика генерации классов использует схемы Velocity для генерации классов.

Я модифицировал шаблон record.vm, чтобы реализовать свой конкретный интерфейс. Существует способ указать расположение каталога скоростей с помощью конфигурации templateDirectory в плагине сборки maven.

Я также переключился на использование SpecificDatumWriter вместо reflectDatumWriter.

<plugin>
  <groupId>org.apache.avro</groupId>
  <artifactId>avro-maven-plugin</artifactId>
   <version>${avro.version}</version>
   <executions>
    <execution>
      <phase>generate-sources</phase>
      <goals>
        <goal>schema</goal>
      </goals>
      <configuration>
         <sourceDirectory>${basedir}/src/main/resources/avro/schema</sourceDirectory>
         <outputDirectory>${basedir}/target/java-gen</outputDirectory>
         <fieldVisibility>private</fieldVisibility>
         <stringType>String</stringType>
         <templateDirectory>${basedir}/src/main/resources/avro/velocity-templates/</templateDirectory>
       </configuration>
    </execution>
  </executions>
</plugin>

Ответ 2

Я решил использовать API ReflectData для создания схемы из класса во время выполнения, а затем использовать ReflectDatumWriter для сериализации. Использование рефлексии будет медленнее. Но похоже, что схема кэшируется внутри. Я отчитаюсь, если увижу проблемы с производительностью.

Schema schema = ReflectData.AllowNull.get().getSchema(sourceObject.getClass());
ReflectDatumWriter<T> reflectDatumWriter = new ReflectDatumWriter<>(schema);

DataFileWriter<T> writer = new DataFileWriter<>(reflectDatumWriter);
try {
    writer.setCodec(CodecFactory.snappyCodec());
    writer.create(schema, new File("data.avro"));
    writer.append(sourceObject);
    writer.close();
}
catch (IOException e) {
    // log exception
}