web-dev-qa-db-ja.com

Avroスキーマのポリモーフィズムと継承

基本クラスを拡張するか、インターフェースを実装するJavaクラスを生成するAvroスキーマ/ IDLを作成することは可能ですか?生成されたJava =クラスはorg.Apache.avro.specific.SpecificRecordBaseを拡張します。したがって、実装が進むべき道かもしれませんが、これが可能かどうかはわかりません。

継承セマンティクスよりも多くの関連付けを使用して、特定のスキーマごとに明示的な「タイプ」フィールドを定義する提案のある例を見てきました。

基本クラスは、ファクトリクラスや、コードの他の部分で<T extends BaseObject>などのジェネリックを使用して頻繁に使用しています。現在、継承をサポートするJSONスキーマからコードを生成しました。

別の副次的な質問:IDLを使用して、プロトコル定義なしでレコードのみを定義できますか?コンパイラがprotocolキーワードの欠落について文句を言うので、答えはノーだと思います。

感謝します!ありがとう。

25
bsam

私はこの問題を解決するためのより良い方法を見つけました。 Avroのスキーマ生成ソースを見ると、内部的にクラス生成ロジックがVelocityスキーマを使用してクラスを生成していることがわかりました。

record.vmテンプレートを変更して、特定のインターフェイスも実装しました。 MavenビルドプラグインのtemplateDirectory構成を使用して、velocityディレクトリの場所を指定する方法があります。

また、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>
15
bsam

この質問にも同様の問題があることがわかりました。私の場合、マーカーインターフェイスを課すだけで、一部タイプにのみ課す必要がありました(後で特定のクラスを区別するため)。あなたの答えのおかげで、私はrecord.vmテンプレートの構造を深く掘り下げました。 "javaAnnotation": "my.full.AnnotationName"定義JSONで.avscキーを定義できることがわかりました。次に、@my.full.AnnotationNameが生成されたクラスに追加されます。

確かに、このソリューションは最終的にマーカーインターフェイス上に構築されていませんが、私の目的には十分であり、テンプレートをそのままにしておくことは大きな利点です。

1

ReflectData AP​​Iを使用して実行時にクラスからスキーマを生成し、次に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
}
1
bsam