public abstract class BasicAnnotationProcessor
extends javax.annotation.processing.AbstractProcessor
Processor
implementation that defers processing of Element
s to later
rounds if they cannot be processed.
Subclasses put their processing logic in BasicAnnotationProcessor.ProcessingStep
implementations. The
steps are passed to the processor by returning them in the initSteps()
method, and can
access the ProcessingEnvironment
using AbstractProcessor.processingEnv
.
Any logic that needs to happen once per round can be specified by overriding
postRound(RoundEnvironment)
.
ProcessingStep
. This helps processors to avoid many common pitfalls, such as
ErrorType
instances, ClassCastException
s and badly coerced types.
A non-package element is considered well-formed if its type, type parameters, parameters,
default values, supertypes, annotations, and enclosed elements are. Package elements are treated
similarly, except that their enclosed elements are not validated. See
SuperficialValidation.validateElement(Element)
for details.
The primary disadvantage to this validation is that any element that forms a circular
dependency with a type generated by another BasicAnnotationProcessor
will never compile
because the element will never be fully complete. All such compilations will fail with an error
message on the offending type that describes the issue.
ProcessingStep
can defer elementsEach ProcessingStep
can defer elements by including them in the set returned by
BasicAnnotationProcessor.ProcessingStep.process(SetMultimap)
; elements deferred by a step will be passed back to
that step in a later round of processing.
This feature is useful when one processor may depend on code generated by another,
independent processor, in a way that isn't caught by the well-formedness check described above.
For example, if an element A
cannot be processed because processing it depends on the
existence of some class B
, then A
should be deferred until a later round of
processing, when B
will have been generated by another processor.
If A
directly references B
, then the well-formedness check will correctly
defer processing of A
until B
has been generated.
However, if A
references B
only indirectly (for example, from within a method
body), then the well-formedness check will not defer processing A
, but a processing step
can reject A
.
Modifier and Type | Class and Description |
---|---|
private static class |
BasicAnnotationProcessor.ElementName
A package or type name.
|
static interface |
BasicAnnotationProcessor.ProcessingStep
The unit of processing logic that runs under the guarantee that all elements are complete and
well-formed.
|
Modifier and Type | Field and Description |
---|---|
private java.util.Set<BasicAnnotationProcessor.ElementName> |
deferredElementNames |
private javax.lang.model.util.Elements |
elements |
private com.google.common.collect.SetMultimap<BasicAnnotationProcessor.ProcessingStep,BasicAnnotationProcessor.ElementName> |
elementsDeferredBySteps |
private javax.annotation.processing.Messager |
messager |
private java.lang.String |
processorName |
private com.google.common.collect.ImmutableList<? extends BasicAnnotationProcessor.ProcessingStep> |
steps |
Constructor and Description |
---|
BasicAnnotationProcessor() |
Modifier and Type | Method and Description |
---|---|
private com.google.common.collect.ImmutableMap<java.lang.String,com.google.common.base.Optional<? extends javax.lang.model.element.Element>> |
deferredElements()
Returns the previously deferred elements.
|
private static void |
findAnnotatedElements(javax.lang.model.element.Element element,
com.google.common.collect.ImmutableSet<? extends java.lang.Class<? extends java.lang.annotation.Annotation>> annotationClasses,
com.google.common.collect.ImmutableSetMultimap.Builder<java.lang.Class<? extends java.lang.annotation.Annotation>,javax.lang.model.element.Element> annotatedElements)
Adds
element and its enclosed elements to annotatedElements if they are
annotated with any annotations in annotationClasses . |
private static javax.lang.model.element.TypeElement |
getEnclosingType(javax.lang.model.element.Element element)
Returns the nearest enclosing
TypeElement to the current element, throwing
an IllegalArgumentException if the provided Element is a
PackageElement or is otherwise not enclosed by a type. |
private com.google.common.collect.ImmutableSet<? extends java.lang.Class<? extends java.lang.annotation.Annotation>> |
getSupportedAnnotationClasses() |
com.google.common.collect.ImmutableSet<java.lang.String> |
getSupportedAnnotationTypes()
Returns the set of supported annotation types as a collected from registered
processing steps.
|
private com.google.common.collect.ImmutableSetMultimap<java.lang.Class<? extends java.lang.annotation.Annotation>,javax.lang.model.element.Element> |
indexByAnnotation(java.util.Set<BasicAnnotationProcessor.ElementName> annotatedElements) |
void |
init(javax.annotation.processing.ProcessingEnvironment processingEnv) |
protected abstract java.lang.Iterable<? extends BasicAnnotationProcessor.ProcessingStep> |
initSteps()
Creates processing steps for this processor.
|
protected void |
postProcess()
Deprecated.
use
postRound(RoundEnvironment) instead |
protected void |
postRound(javax.annotation.processing.RoundEnvironment roundEnv)
An optional hook for logic to be executed at the end of each round.
|
private void |
process(com.google.common.collect.ImmutableSetMultimap<java.lang.Class<? extends java.lang.annotation.Annotation>,javax.lang.model.element.Element> validElements)
Processes the valid elements, including those previously deferred by each step.
|
boolean |
process(java.util.Set<? extends javax.lang.model.element.TypeElement> annotations,
javax.annotation.processing.RoundEnvironment roundEnv) |
private java.lang.String |
processingErrorMessage(java.lang.String target) |
private void |
reportMissingElements(java.util.Map<java.lang.String,? extends com.google.common.base.Optional<? extends javax.lang.model.element.Element>> missingElements,
java.util.Collection<BasicAnnotationProcessor.ElementName> missingElementNames) |
private com.google.common.collect.ImmutableSetMultimap<java.lang.Class<? extends java.lang.annotation.Annotation>,javax.lang.model.element.Element> |
validElements(com.google.common.collect.ImmutableMap<java.lang.String,com.google.common.base.Optional<? extends javax.lang.model.element.Element>> deferredElements,
javax.annotation.processing.RoundEnvironment roundEnv)
Returns the valid annotated elements contained in all of the deferred elements.
|
private final java.util.Set<BasicAnnotationProcessor.ElementName> deferredElementNames
private final com.google.common.collect.SetMultimap<BasicAnnotationProcessor.ProcessingStep,BasicAnnotationProcessor.ElementName> elementsDeferredBySteps
private final java.lang.String processorName
private javax.lang.model.util.Elements elements
private javax.annotation.processing.Messager messager
private com.google.common.collect.ImmutableList<? extends BasicAnnotationProcessor.ProcessingStep> steps
public final void init(javax.annotation.processing.ProcessingEnvironment processingEnv)
init
in interface javax.annotation.processing.Processor
init
in class javax.annotation.processing.AbstractProcessor
protected abstract java.lang.Iterable<? extends BasicAnnotationProcessor.ProcessingStep> initSteps()
AbstractProcessor.processingEnv
is guaranteed to be set when this method is invoked.@Deprecated protected void postProcess()
postRound(RoundEnvironment)
insteadprotected void postRound(javax.annotation.processing.RoundEnvironment roundEnv)
private com.google.common.collect.ImmutableSet<? extends java.lang.Class<? extends java.lang.annotation.Annotation>> getSupportedAnnotationClasses()
public final com.google.common.collect.ImmutableSet<java.lang.String> getSupportedAnnotationTypes()
getSupportedAnnotationTypes
in interface javax.annotation.processing.Processor
getSupportedAnnotationTypes
in class javax.annotation.processing.AbstractProcessor
public final boolean process(java.util.Set<? extends javax.lang.model.element.TypeElement> annotations, javax.annotation.processing.RoundEnvironment roundEnv)
process
in interface javax.annotation.processing.Processor
process
in class javax.annotation.processing.AbstractProcessor
private com.google.common.collect.ImmutableMap<java.lang.String,com.google.common.base.Optional<? extends javax.lang.model.element.Element>> deferredElements()
private void reportMissingElements(java.util.Map<java.lang.String,? extends com.google.common.base.Optional<? extends javax.lang.model.element.Element>> missingElements, java.util.Collection<BasicAnnotationProcessor.ElementName> missingElementNames)
private java.lang.String processingErrorMessage(java.lang.String target)
private com.google.common.collect.ImmutableSetMultimap<java.lang.Class<? extends java.lang.annotation.Annotation>,javax.lang.model.element.Element> validElements(com.google.common.collect.ImmutableMap<java.lang.String,com.google.common.base.Optional<? extends javax.lang.model.element.Element>> deferredElements, javax.annotation.processing.RoundEnvironment roundEnv)
private void process(com.google.common.collect.ImmutableSetMultimap<java.lang.Class<? extends java.lang.annotation.Annotation>,javax.lang.model.element.Element> validElements)
private com.google.common.collect.ImmutableSetMultimap<java.lang.Class<? extends java.lang.annotation.Annotation>,javax.lang.model.element.Element> indexByAnnotation(java.util.Set<BasicAnnotationProcessor.ElementName> annotatedElements)
private static void findAnnotatedElements(javax.lang.model.element.Element element, com.google.common.collect.ImmutableSet<? extends java.lang.Class<? extends java.lang.annotation.Annotation>> annotationClasses, com.google.common.collect.ImmutableSetMultimap.Builder<java.lang.Class<? extends java.lang.annotation.Annotation>,javax.lang.model.element.Element> annotatedElements)
element
and its enclosed elements to annotatedElements
if they are
annotated with any annotations in annotationClasses
. Does not traverse to member types
of element
, so that if Outer
is passed in the example below, looking for
@X
, then Outer
, Outer.foo
, and Outer.foo()
will be added to the
multimap, but neither Inner
nor its members will.
@X class Outer {
@X Object foo;
@X void foo() {}
@X static class Inner {
@X Object bar;
@X void bar() {}
}
}
private static javax.lang.model.element.TypeElement getEnclosingType(javax.lang.model.element.Element element)
TypeElement
to the current element, throwing
an IllegalArgumentException
if the provided Element
is a
PackageElement
or is otherwise not enclosed by a type.