Polymorphism and inheritance in Avro schemas

坚强是说给别人听的谎言 提交于 2019-12-02 20:26:56
bsam

I found a better way to solve this problem. Looking at the Schema generation source in Avro, I figured out that internally the class generation logic uses Velocity schemas to generate the classes.

I modified the record.vm template to also implement my specific interface. There is a way to specify the location of velocity directory using the templateDirectory configuration in the maven build plugin.

I also switched to using SpecificDatumWriter instead of 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>
bsam

I decided to use the ReflectData API to generate the Schema from the class at runtime and then use the ReflectDatumWriter for serialization. Use of reflection will be slower. But, it looks like the schema is cached internally. I will report back if I see performance issues.

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
}

I found this question having similar problem. In my case I needed just to impose marker interface and only to some types (to distinguish particular classes later). Thanks to your answer, I dug deeper into structure of record.vm template. I found out it's possible to define "javaAnnotation": "my.full.AnnotationName" key in .avsc definition JSON. @my.full.AnnotationName is then added to generated class.

Admittedly, this solution is not built on marker interface finally, though for my purpose is good enough and keeping template untouched is big advantage.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!