To make your annotation processor incremental you must declare it in META-INF in incremental.annotation.processors
file:
your.fully.qualified.annotation.processor.name,category
There are three categories of annotation processor to choose from: dynamic, isolating and aggregating.
Basically at a high-level:
- dynamic: when your processor can only decide at runtime whether it is incremental or not
- isolating: when your processor will work with each type annotated with your annotation in isolation (one input for one or more output)
- aggregation: when your processor need aggregate several inputs (type annotated with your annotation) to making one or more output
But, each category has limitations that you have to consider:
Dynamic limitations
They must generate their files using the Filer API. Writing files any other way will result in silent failures later on, as these files won’t be cleaned up correctly. If your processor does this, it cannot be incremental.
They must not depend on compiler-specific APIs like com.sun.source.util.Trees
. Gradle wraps the processing APIs, so attempts to cast to compiler-specific types will fail. If your processor does this, it cannot be incremental, unless you have some fallback mechanism.
If they use Filer#createResource, the location
argument must be one of these values from StandardLocation: CLASS_OUTPUT
, SOURCE_OUTPUT
, or NATIVE_HEADER_OUTPUT
. Any other argument will disable incremental processing.
Isolating limitations
They must make all decisions (code generation, validation messages) for an annotated type based on information reachable from its AST. This means you can analyze the types' super-class, method return types, annotations etc., even transitively. But you cannot make decisions based on unrelated elements in the RoundEnvironment. Doing so will result in silent failures because too few files will be recompiled later. If your processor needs to make decisions based on a combination of otherwise unrelated elements, mark it as "aggregating" instead.
They must provide exactly one originating element for each file generated with the Filer API. If zero or many originating elements are provided, Gradle will recompile all source files.
Aggregation limitations
From Gradle documentation
PS: for dynamic, you also have to override getSupportedOptions()
method to specify the category: isolating or aggregation. See the Gradle documentation for more details.