2

I have my annotation processor:

public class MyAnnotationProcessor extends AbstractProcessor {
    ...

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        // Here I deal with the annotated element
         ...

        // use JavaPoet to generate Java source file
        TypeSpec generatedClazz = generate_code();
        JavaFile javaFile = JavaFile.builder("com.my.foo", generatedClazz).build();
        javaFile.writeTo(filer);
    }

}

After processing annotated element in above process callback, I use JavaPoet to generate java source code & create the Java file for the code. When build my project, everything works except that the generated java source code file by default goes to build/generated/sources/myApp/com/my/foo. How can I make the generated Java file to be located in my project's source code location src/main/java/com/my/foo ?

My gradle build:

plugins {
    id 'java'
}

group 'com.my.app'
version '1.0-SNAPSHOT'

sourceCompatibility = 1.8

repositories {
    mavenCentral()
}

dependencies {

    testImplementation 'junit:junit:4.12'

    implementation 'com.squareup:javapoet:1.11.1'
    implementation 'com.google.guava:guava:28.1-jre'
}
Leem.fin
  • 40,781
  • 83
  • 202
  • 354
  • Can you clarify why you want to do this, or what you are trying to achieve? Unless I am misremembering, the annotation processor will error out of the class it is trying to create already exists in the normal sources, so running what you ask for once will work, and every time after that will cause an error. Also: add details about how you are building (gradle, maven, etc), so that an answer can be made that helps your setup. – Colin Alworth Oct 09 '19 at 21:09
  • I want to generate code to my source folder in annotation processor. I build it in my Intellj IDE. – Leem.fin Oct 10 '19 at 06:05
  • If you can go a little further and explain why, I can try to help with an answer, otherwise all I can say is that this isn't possible or reasonable. Remember that in IntelliJ, even if it builds to the build/generated/ directory, you can still view that code. Would you expect to edit the generated code afterward? Commit it to version control? Have other generated code be based on it? etc. – Colin Alworth Oct 10 '19 at 13:05
  • 1
    I just want to know whether it is possible to use JavaPoet to generate code under `src/` directory instead of the `build/` directory. That's the motivation of my question, no other reason, it is my curiosity. I want to know whether it is possible. Yes, I want to edit the generated code afterwards, is it possible? If it is impossible it is also an answer to my question. I updated my question with gradle build. I don't know how I can explain further. – Leem.fin Oct 10 '19 at 19:50
  • Short answer: yes it is possible with JavaPoet, but no, not with annotation processors. I'll write up something longer later, but in short you'll just call writeTo() on a different writer or directly on a file to make it work in your source dir. – Colin Alworth Oct 10 '19 at 20:54

2 Answers2

1

The bad news: Annotation processors can't do this - the nature of how their rounds work mean that it isn't going to make sense to generate sources in the same directory where "actual" sources live, since those generated sources will be treated as inputs the next time the annotation processor runs.

Good news: JavaPoet is agnostic of how you actually invoke it, so you can just write a simple main() that does the code generation, and either ask your IDE to invoke it when it builds, or attach it to your gradle build. If you plan on manually editing the sources after they are generated, you probably don't want this to happen, since you likely intend your manual changes to be kept instead of being overwritten each time you build.

The JavaFile.writeTo(...) method has several overrides, and only one of them takes the annotation processor Filer. Using the Filer has some advantages - it is very clear where you intend the class to be written - but JavaFile.writeTo(File directory) is also meant to be used in this way. You don't pass it the actual file where you want the MyClass.java to be, just the source directory you want to write to. In your case, this would be roughly javaFile.writeTo(new File("myProject/src/main/java")).

You probably still should parameterize how to invoke this main, so that it knows what inputs to use, how to understand your existing sources, etc. On the other hand, if your generate_code() doesn't need any existing sources from the same project to run, this should be quite straightforward.

Colin Alworth
  • 17,801
  • 2
  • 26
  • 39
  • Your example of `javaFile.writeTo("myProject/src/main/java")` is wrong, there is no such API `writeTo(java.lang.String)` in JavaFile – Leem.fin Oct 11 '19 at 19:22
  • Fixed, sorry about that - i had said the right think just two sentences before, and then screwed it up... – Colin Alworth Oct 11 '19 at 23:02
  • I have a custom annotation, I need to process the annotated element in annotation processor then generate java code under `src/`. So, based on your answer it is impossible, right? What about generate unit test code to `src/main/teset` with annotation processor, is it possible? – user842225 Oct 12 '19 at 14:57
  • As far as I know you are out of luck @user842225 - annotation processors must work in rounds or they won't make sense and the compiler can't invoke them - though if you generate into your build directory, they work equally well for "main" or "test". The real question to me is: Why do you require generating code under `src`? If you can't use your IDE's or build tool's ability to handle generated sources in your build directory for some reason, then it seems you must define your own tooling here. – Colin Alworth Oct 12 '19 at 17:09
1

Not sure about gradle but with maven you can defined the generated source directory using below tab in maven-compiler-plugin.

<generatedSourcesDirectory>
     ${project.basedir}/src/main/java
</generatedSourcesDirectory>

For complete example check the below link.

https://www.thetechnojournals.com/2019/12/annotation-processor-to-generate-dto.html

Ashok Prajapati
  • 374
  • 2
  • 7