Annotation Processor cannot read annotations on a annotation class parameter

Viewed 244

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());
0 Answers
Related