1

I have a basic Annotation Processor

@SupportedAnnotationTypes("example.Annotation")
public class Processor extends AbstractProcessor {
    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        for (TypeElement annotation : annotations) {
            Set<? extends Element> elementsAnnotatedWith = roundEnv.getElementsAnnotatedWith(annotation);
            for (Element element : elementsAnnotatedWith) {
                TypeElement typeElement = (TypeElement) element;
                // Here, typeElement.getQualifiedName() is accessible, but not the code nor file path.
            }
        }
        return false;
    }
}

This annotation can only be used on classes. I know the target class is not compiled so reflective access is not possible but I would like to get the class code as String to parse in my own way instead of using this API.

Is it possible? I know I can get qualified name but where to look for the file?

6
  • Do you really need the complete source code, or reflection informations (method signatures, field declaration, inheritance, ...) is enough ? Commented May 8, 2021 at 14:30
  • @Tigger I already hade a lot of code based on parsing class code so I wanted to re-use it. But there seems to be no way so I had to rewrite my code using this API (processingEnv.getElementUtils()). Commented May 8, 2021 at 17:36
  • Actually, I still need the other method. For copying a method from the annotated class to the generated class... Commented May 8, 2021 at 17:46
  • Since it happens before compilation, all the source files you need have to be there, somewhere on the file system, right ? If so, I bet there is some environment variable you could use. How do you compile/build your library (maven, gradle, ...) ? Commented May 8, 2021 at 17:54
  • I use Gradle but won't that make the annotation processor only work for me? Commented May 8, 2021 at 18:11

1 Answer 1

2

The source code of a TypeElement can be loaded like this:

private String loadSource(TypeElement typeElement) throws IOException {
    final FileObject source = processingEnv.getFiler().getResource(
        StandardLocation.SOURCE_PATH,
        ((PackageElement) typeElement.getEnclosingElement()).getQualifiedName(),
        typeElement.getSimpleName() + ".java");
    
    try (Reader reader = source.openReader(true)) {
        final StringBuilder builder = new StringBuilder();
        final char[] buf = new char[1024];
        int read;
        while ((read = reader.read(buf)) != -1) {
            builder.append(buf, 0, read);
        }
        return builder.toString();
    }
}

The tested Processor jar contains a META-INF/services/javax.annotation.processing.Processor file, no need to specify -process option:

  • Maven : OK
  • Gradle : extra configuration needed, assuming src/main/java is the source directory
tasks.withType(JavaCompile) {
    configure(options) {
        options.setSourcepath(project.files('src/main/java'))
    }
}
  • Command line: add -sourcepath option:

javac -cp path/to/processor.jar -sourcepath path/to/sources path/to/JavaFile.java

Sign up to request clarification or add additional context in comments.

2 Comments

Unfortunately SOURCE_PATH is null in Gradle :(
I found a way to make it work with Gradle, and updated my answer. I hope it will work for you.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.