avro - sencillos - que es herencia en java
Polimorfismo y herencia en esquemas avro. (3)
Decidí usar la API ReflectData
para generar el esquema de la clase en el tiempo de ejecución y luego usar el ReflectDatumWriter
para la serialización. El uso de la reflexión será más lento. Pero, parece que el esquema se almacena en caché internamente. Informaré si veo problemas de rendimiento.
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
}
¿Es posible escribir un esquema Avro / IDL que generará una clase Java que amplíe una clase base o implemente una interfaz? Parece que la clase Java generada extiende el org.apache.avro.specific.SpecificRecordBase
. Por lo tanto, los implementos podrían ser el camino a seguir. Pero, no sé si esto es posible.
He visto ejemplos con sugerencias para definir un campo de "tipo" explícito en cada esquema específico, con más de una asociación que semántica de herencia.
Uso mi clase base en gran medida en mis clases de fábrica y otras partes del código con genéricos como <T extends BaseObject>
. Actualmente, tenía el código generado a partir del esquema JSON, que admite herencia.
Otra pregunta adicional: ¿puede usar IDL para definir solo los registros sin la definición del protocolo? Creo que la respuesta es no porque el compilador se queja de la palabra clave del protocolo que falta.
Ayuda apreciada! Gracias.
Encontré esta pregunta teniendo un problema similar. En mi caso, solo necesitaba imponer una interfaz de marcador y solo a algunos tipos (para distinguir clases particulares más adelante). Gracias a su respuesta, profundicé más en la estructura de la plantilla record.vm
. Descubrí que es posible definir la "javaAnnotation": "my.full.AnnotationName"
en .avsc
definition JSON. @my.full.AnnotationName
luego se agrega a la clase generada.
Es cierto que esta solución no se basa en la interfaz del marcador finalmente, aunque para mi propósito es lo suficientemente bueno y mantener la plantilla intacta es una gran ventaja.
Encontré una mejor manera de resolver este problema. Mirando la fuente de generación de esquemas en Avro, descubrí que internamente la lógica de generación de clases usa los esquemas de Velocity para generar las clases.
record.vm
plantilla record.vm
para implementar también mi interfaz específica. Hay una forma de especificar la ubicación del directorio de velocidad mediante la configuración de templateDirectory
en el complemento de compilación de Maven.
También reflectDatumWriter
a usar SpecificDatumWriter
lugar de 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>