是否可以编写一个Avro架构/ IDL来生成扩展基类或实现接口的Java类?
似乎生成的Java类扩展了org.apache.avro.specific.SpecificRecordBase
。因此,工具可能是要走的路。但是,我不知道这是否可能。
我看过一些示例,建议在每个特定模式中定义一个显式的“类型”字段,其中包含的关联多于继承语义。
我在我的工厂类和代码的其他部分使用我的基类,使用像<T extends BaseObject>
这样的泛型。目前,我有从JSON Schema生成的代码,它支持继承。
另一个侧面问题:您是否可以使用IDL来定义没有协议定义的记录?我认为答案是否定的,因为编译器抱怨缺少协议关键字。
帮助表示感谢!感谢。
答案 0 :(得分:15)
我找到了解决此问题的更好方法。看一下Avro中的Schema生成源,我发现在类内部,类生成逻辑使用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>
答案 1 :(得分:1)
我决定使用ReflectData
API在运行时从类生成Schema,然后使用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
}
答案 2 :(得分:1)
如果我在这里写出我正是为这种情况创建了maven插件-https://github.com/tunguski/interfacer,希望对其他人有帮助。
它会检查自动生成的类,并检查它们是否符合特定包中classpath上的接口。如果是,则将接口添加到该类。它与通用接口兼容,至少在我必须处理的基本示例中。
该插件不是avro专用的,可以作为生成的代码后处理器使用,因此也可以在其他情况下使用。
map(lambda val: 10 if val < 2 else 50, [1,2,3]))
<!--
post process avro generated sources and add interfaces from package
pl.matsuo.interfacer.showcase to every generated class that has
all methods from specific interface
-->
<plugin>
<groupId>pl.matsuo.interfacer</groupId>
<artifactId>interfacer-maven-plugin</artifactId>
<version>0.0.6</version>
<executions>
<execution>
<configuration>
<interfacesDirectory>${project.basedir}/src/main/java</interfacesDirectory>
<interfacePackage>pl.matsuo.interfacer.showcase</interfacePackage>
</configuration>
<goals>
<goal>add-interfaces</goal>
</goals>
</execution>
</executions>
</plugin>
答案 3 :(得分:0)
我发现这个问题也有类似的问题。就我而言,我只需要强加 marker interface ,并且只强加 some 类型(以便以后区分特定的类)。感谢您的回答,我更深入地研究了record.vm
模板的结构。我发现可以在"javaAnnotation": "my.full.AnnotationName"
定义JSON中定义.avsc
键。然后将@my.full.AnnotationName
添加到生成的类中。
诚然,此解决方案最终不是基于标记器接口构建的,尽管对我来说足够好,并且保持模板不变是很大的优势。
答案 4 :(得分:0)
我遵循https://www.infoq.com/articles/ApacheAvro/来实现继承。这也使多态性成为现实(我需要)。
一分。
在声明时
{"name": "user", "type": com.navteq.avro.FacebookUser },
确保您使用双引号,例如{"name": "user", "type": "com.navteq.avro.FacebookUser" },
如果我不这样做,那我将得到如下错误
> org.apache.avro.SchemaParseException: org.codehaus.jackson.JsonParseException: Unexpected character ('c' (code 99)): expected a valid value (number, String, array, object, 'true', 'false' or 'null')