Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions avro/avro-annotation-processor/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import org.apache.avro.tool.SpecificCompilerTool

buildscript {
dependencies {
classpath "org.apache.avro:avro-tools:1.12.0"
}
}

apply from: "${project.rootDir}/gradle/in-test-generated.gradle"

dependencies {
api project(":annotation-processor-common")
api project(":kora-app-annotation-processor")

testImplementation project(":avro:avro-common")
testImplementation testFixtures(project(":annotation-processor-common"))
}

tasks.register("generateAvroClasses") {
group("build")

var inputDir = "$projectDir/src/test/resources/avro"
var outputDir = "$buildDir/generated/sources/avro"
inputs.dir(inputDir)
outputs.dir(outputDir)
logging.captureStandardOutput(LogLevel.INFO);
logging.captureStandardError(LogLevel.ERROR)

doFirst {
delete outputDir
}

doLast {
var params = ["-bigDecimal", "schema", inputDir.toString(), outputDir.toString()]
new SpecificCompilerTool().run(System.in, System.out, System.err, params)
}
}

test.dependsOn(tasks.generateAvroClasses)
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package ru.tinkoff.kora.avro.annotation.processor;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.event.Level;
import ru.tinkoff.kora.annotation.processor.common.AbstractKoraProcessor;
import ru.tinkoff.kora.annotation.processor.common.LogUtils;
import ru.tinkoff.kora.annotation.processor.common.ProcessingErrorException;
import ru.tinkoff.kora.avro.annotation.processor.reader.AvroReaderGenerator;
import ru.tinkoff.kora.avro.annotation.processor.writer.AvroWriterGenerator;

import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.TypeElement;
import java.util.Set;

public class AvroAnnotationProcessor extends AbstractKoraProcessor {

private static final Logger logger = LoggerFactory.getLogger(AvroAnnotationProcessor.class);

private boolean initialized = false;
private TypeElement avroBinaryAnnotation;
private TypeElement avroJsonAnnotation;
private AvroWriterGenerator writerGenerator;
private AvroReaderGenerator readerGenerator;

@Override
public Set<String> getSupportedAnnotationTypes() {
return Set.of(AvroTypes.avroBinary.canonicalName(), AvroTypes.avroJson.canonicalName());
}

@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
this.avroBinaryAnnotation = processingEnv.getElementUtils().getTypeElement(AvroTypes.avroBinary.canonicalName());
if (this.avroBinaryAnnotation == null) {
return;
}

this.avroJsonAnnotation = processingEnv.getElementUtils().getTypeElement(AvroTypes.avroJson.canonicalName());
this.initialized = true;
this.writerGenerator = new AvroWriterGenerator(processingEnv);
this.readerGenerator = new AvroReaderGenerator(processingEnv);
}

@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
if (!this.initialized) {
return false;
}
if (roundEnv.processingOver()) {
return false;
}

var avroBinaryElements = roundEnv.getElementsAnnotatedWith(this.avroBinaryAnnotation).stream()
.filter(e -> e.getKind().isClass() || e.getKind() == ElementKind.INTERFACE)
.toList();
if (!avroBinaryElements.isEmpty()) {
LogUtils.logElementsFull(logger, Level.DEBUG, "Generating Avro Binary Readers & Writers for", avroBinaryElements);
for (var e : avroBinaryElements) {
try {
this.readerGenerator.generateBinary((TypeElement) e);
} catch (ProcessingErrorException ex) {
ex.printError(this.processingEnv);
}
try {
this.writerGenerator.generateBinary((TypeElement) e);
} catch (ProcessingErrorException ex) {
ex.printError(this.processingEnv);
}
}
}

var avroJsonElements = roundEnv.getElementsAnnotatedWith(this.avroJsonAnnotation).stream()
.filter(e -> e.getKind().isClass() || e.getKind() == ElementKind.INTERFACE)
.toList();
if (!avroJsonElements.isEmpty()) {
LogUtils.logElementsFull(logger, Level.DEBUG, "Generating Avro Json Readers & Writers for", avroBinaryElements);
for (var e : avroJsonElements) {
try {
this.readerGenerator.generateJson((TypeElement) e);
} catch (ProcessingErrorException ex) {
ex.printError(this.processingEnv);
}
try {
this.writerGenerator.generateJson((TypeElement) e);
} catch (ProcessingErrorException ex) {
ex.printError(this.processingEnv);
}
}
}

return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package ru.tinkoff.kora.avro.annotation.processor;

import com.squareup.javapoet.ClassName;

public final class AvroTypes {

private AvroTypes() {}

public static final ClassName avroBinary = ClassName.get("ru.tinkoff.kora.avro.common.annotation", "AvroBinary");
public static final ClassName avroJson = ClassName.get("ru.tinkoff.kora.avro.common.annotation", "AvroJson");

public static final ClassName reader = ClassName.get("ru.tinkoff.kora.avro.common", "AvroReader");
public static final ClassName writer = ClassName.get("ru.tinkoff.kora.avro.common", "AvroWriter");

public static final ClassName schema = ClassName.get("org.apache.avro", "Schema");
public static final ClassName specificData = ClassName.get("org.apache.avro.specific", "SpecificData");
public static final ClassName datumReader = ClassName.get("org.apache.avro.specific", "SpecificDatumReader");
public static final ClassName datumWriter = ClassName.get("org.apache.avro.specific", "SpecificDatumWriter");
public static final ClassName decoderFactory = ClassName.get("org.apache.avro.io", "DecoderFactory");
public static final ClassName encoderFactory = ClassName.get("org.apache.avro.io", "EncoderFactory");
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package ru.tinkoff.kora.avro.annotation.processor;

import ru.tinkoff.kora.annotation.processor.common.NameUtils;

import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;


public final class AvroUtils {

private AvroUtils() {}

public static String classPackage(Elements elements, Element typeElement) {
return elements.getPackageOf(typeElement).getQualifiedName().toString();
}

public static String writerBinaryName(Element typeElement) {
return NameUtils.generatedType(typeElement, "AvroBinaryWriter");
}

public static String writerBinaryName(Types types, TypeMirror typeMirror) {
var typeElement = types.asElement(typeMirror);
return writerBinaryName(typeElement);
}

public static String writerJsonName(Element typeElement) {
return NameUtils.generatedType(typeElement, "AvroJsonWriter");
}

public static String writerJsonName(Types types, TypeMirror typeMirror) {
var typeElement = types.asElement(typeMirror);
return writerJsonName(typeElement);
}

public static String readerBinaryName(TypeElement typeElement) {
return NameUtils.generatedType(typeElement, "AvroBinaryReader");
}

public static String readerBinaryName(Types types, TypeMirror typeMirror) {
var typeElement = types.asElement(typeMirror);
return readerBinaryName((TypeElement) typeElement);
}

public static String readerJsonName(TypeElement typeElement) {
return NameUtils.generatedType(typeElement, "AvroJsonReader");
}

public static String readerJsonName(Types types, TypeMirror typeMirror) {
var typeElement = types.asElement(typeMirror);
return readerJsonName((TypeElement) typeElement);
}
}
Loading
Loading