Полиморфизм и наследование в схемах Авро
Можно ли написать схему 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
}