I'm trying to write a Java annotationProcessor that finds classes with a CreateTable annotation that contains many parameters. The annotation on my MessagesTable class has a parameter that refers to the ConversationsTable class, which is also annotated with CreateTable I figured out how to get a TypeMirror for ConversationsTable, but foreignTypeMirror.getAnnotation(CreateTable.class) and similar methods all return null, rather than retrieving the annotation. How can I read the parameters from the CreateTable annotation on the ConversationsTable class? The annotation processor is a isolating processor. I'm not entirely certain what that means, but changing it to aggregation does not seem to affect anything.
The relevant annotations:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
public @interface CreateTable {
Column[] columns();
}
@Target({})
public @interface Column {
ColumnForeignKey foreignKey() default @ColumnForeignKey(Void.class);
}
@Target({})
public @interface ColumnForeignKey {
Class<?> value();
}
The annotated classes:
@CreateTable(columns = {})
public interface ConversationsTable { }
@CreateTable(
columns = {
@Column(foreignKey = @ColumnForeignKey(ConversationsTable.class))
}
)
public interface MessagesTable {}
Exact error:
MessagesTable.java:43: Note: [snip].ConversationsTable has 0 annotationMirrors
MessagesTable.java:43: error: Column conversation_id foreign key references class [snip].ConversationsTable without CreateTable annotation
CreateTableMethodBuilder#appendColumnForeignKey is the method that parses the ColumnForeignKey annotation but is unable to find CreateTable on the ConversationsTable class.
private void appendColumnForeignKey(StringBuilder createTableString, TypeElement typeElement, String columnName, Column column) {
ColumnForeignKey foreignKey = column.foreignKey();
TypeMirror foreignTypeMirror = ProcessorHelpers.getTypeMirror(foreignKey::value);
CreateTable foreignTableAnnot = foreignTypeMirror.getAnnotation(CreateTable.class);
//begin debugging
if (types.isSameType(am.getAnnotationType(), createTableElement))
messager.info(typeElement, "%s has annotation %s (CreateTable=yes)", foreignTypeMirror, am);
else
messager.info(typeElement, "%s has annotation %s (CreateTable=no)", foreignTypeMirror, am);
//end debugging
if (foreignTableAnnot == null) {
messager.error(typeElement,
"Column %s foreign key references class %s without CreateTable annotation",
columnName,
foreignTypeMirror);
return;
}
I believe the rest of this code is unrelated, but provide it for more completeness.
ProcessorHelpers#getTypeMirror
public static TypeMirror getTypeMirror(Supplier<Class<?>> supplier) {
try {
supplier.get();
throw new IllegalStateException("supplier did not return a class");
} catch (MirroredTypeException mte) {
return mte.getTypeMirror();
}
}
CreateTableMethodBuilder#appendColumnDefs
private void appendColumnDefs(StringBuilder createTableString, TypeElement typeElement, Column[] columns) {
for (int i = 0; i < columns.length; i++) {
Column column = columns[i];
...
appendColumnForeignKey(createTableString, typeElement, column.name(), column);
}
CreateTableMethodBuilder#getCreateTableMethod
public CodeBlock getCreateTableMethod(TypeElement typeElement, CreateTable createTable) {
StringBuilder createTableString = new StringBuilder();
...
appendColumnDefs(createTableString, typeElement, createTable.columns());
My processor has this "boilerplate", which I'm pretty sure isn't relevant
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
if (annotations.isEmpty())
return true;
Set<? extends Element> annotated =
roundEnv.getElementsAnnotatedWith(CreateTable.class)
.stream()
.filter(e -> e instanceof TypeElement)
.collect(Collectors.toSet());
messager.info(annotations.iterator().next(), "Starting TableProcessor round on %d types", annotations.size());
for (Element annotatedElement : annotated) {
TypeElement typeElement = (TypeElement) annotatedElement;
messager.info(typeElement, "Running TableProcessor processor on %s", typeElement);
CreateTable createTable = typeElement.getAnnotation(CreateTable.class);
String packageName = elements.getPackageOf(typeElement).getQualifiedName().toString();
String typeName = typeElement.getSimpleName().toString();
ClassName className = ClassName.get(packageName, typeName);
ClassName generatedClassName = ClassName.get(packageName, className + "Sql");
TypeSpec.Builder classBuilder = TypeSpec.classBuilder(generatedClassName)
.addModifiers(Modifier.PUBLIC)
.addAnnotation(Keep.class);
getCreateTableBuilder.addCode(
new CreateTableMethodBuilder(processingEnv, messager)
.getCreateTableMethod(typeElement, createTable));
classBuilder.addMethod(getCreateTableBuilder.build());