I'm making a library that includes an annotation processor
.
├── lib
│ ├── build.gradle
│ └── src
│ ├── main
│ │ ├── java
│ │ │ └── demo
│ │ │ ├── MyAnnotation.java
│ │ │ └── MyAnnotationProcessor.java
│ │ └── resources
│ └── test
│ ├── java
│ │ └── demo
│ │ └── MyAnnotationProcessorTest.java
│ └── resources
└── settings.gradle
I would like to use @MyAnnotation
in MyAnnotationProcessorTest.java
But it doesn't look like gradle is processing that annotation at all when I build nor test this project.
For the sake of debugging, the annotation files just look like
package demo;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.MODULE, ElementType.PACKAGE, ElementType.TYPE_USE, ElementType.PARAMETER, ElementType.CONSTRUCTOR, ElementType.LOCAL_VARIABLE, ElementType.TYPE_PARAMETER, ElementType.ANNOTATION_TYPE, ElementType.RECORD_COMPONENT})
@Retention(RetentionPolicy.SOURCE)
public @interface MyAnnotation { }
package demo;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.tools.Diagnostic;
import com.google.auto.service.AutoService;
@SupportedAnnotationTypes("demo.MyAnnotation")
@AutoService(Processor.class)
public class MyAnnotationProcessor extends AbstractProcessor {
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latest();
}
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, ">>>>> process called <<<<<");
return true;
}
}
and the test file just sprays a lot of @MyAnnotation
everywhere.
My build.gradle
is
plugins {
id 'java-library'
}
repositories {
mavenCentral()
}
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter:5.9.1'
implementation 'com.google.auto.service:auto-service:1.1.1'
annotationProcessor 'com.google.auto.service:auto-service:1.1.1'
}
// Apply a specific Java toolchain to ease working on different environments.
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
tasks.named('test') {
// Use JUnit Platform for unit tests.
useJUnitPlatform()
}
But when I gradle build
or gradle test
, there is no output from my annotation processor.
I made a second project that specifies dependencies { annotationProcessor 'my-annotation-processor-project' }
to test that the annotation processor works, and when I build that project, the annotation processor's messages are logged. I would like them to also be logged when the annotation is used in the annotation processor's project itself.
How can I test and use a compile-time annotation processor within the same project that defines it?
I've found a solution that works for me. It feels a bit janky, not sure if this would be recommended, so I'm also looking forward to better answers.
I made a second gradle "module" that does the testing
.
├── lib
│ ├── build.gradle
│ └── src
│ └── main
│ └── java
│ └── demo
│ ├── MyAnnotation.java
│ └── MyAnnotationProcessor.java
├── test
│ ├── build.gradle
│ └── src
│ └── test
│ └── java
│ └── demo
│ └── MyAnnotationProcessorTest.java
└── settings.gradle
settings.gradle
has to have include('test')
added (under where you probably already have include('lib')
Then lib/build.gradle
can have all the testing removed:
lib/build.gradle
plugins {
id 'java-library'
}
repositories {
mavenCentral()
}
dependencies {
implementation 'com.google.auto.service:auto-service:1.1.1'
annotationProcessor 'com.google.auto.service:auto-service:1.1.1'
}
// Apply a specific Java toolchain to ease working on different environments.
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
and test/build.gradle
should be set up for testing
test/build.gradle
plugins {
id 'java'
}
repositories {
mavenCentral()
}
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter:5.9.1'
testImplementation project(':lib')
testAnnotationProcessor project(':lib')
}
// Apply a specific Java toolchain to ease working on different environments.
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
tasks.named('test') {
// Use JUnit Platform for unit tests.
useJUnitPlatform()
}
I don't think any of the ./test
module is going to get included in the ./builds/libs/demo.jar
build result, but I'm not sure.