Dynamic Active Annotations

You may have noticed throughout the documentation, that tapir uses a lot of active annotations in various modules. Those active annotations are responsible for generating additional Java code from the Xtend code. You might encounter situations in which the generated code is not enough or obstructs you somehow. In such cases you are able to implement an own annotation processor and override tapir’s behaviour.

Caution
For this chapter we assume that you are already familiar with active annotations. If not, you might want to take another look at the Xtend chapter of this documentation.

The active annotations which bind their corresponding annotation processors in a lazy way are called dynamic active annotations in tapir. Such annotations are annotated with @DynamicActive. The potential annotation processors are annotated with @AnnotationProcessor. To determine which annotation processor is the one generating the code for a dynamic active annotation, Spring’s @Order annotation is used. As a higher order is prefered over a lower order, you are able to overwrite tapir’s annotation processor in submodules.

Caution
When you implement an own annotation processor, please make sure that it does not have any kind of state (e.g. a field) to transport data between the annotation processing phases. It is neither guaranteed that the processor is not reused for various annotated elements nor that the same instance is used for two phases of the same annotated element.

Parameter.xtend

@Retention(RetentionPolicy.RUNTIME)
@Target(#[ElementType.FIELD, ElementType.PARAMETER])
@DynamicActive
public annotation Parameter {
    ...
}

ParameterValidator.xtend

@AnnotationProcessor(#[Parameter, IteratedParameter])
@Order(-10000)
class ParameterValidator implements ValidationParticipant<NamedElement> {
    ...
}

The above example shows the dynamic active Parameter annotation from the data provider chapter and the corresponding ParameterValidator. Note that the ParameterValidator is responsible to process more than one annotation and has an order of -10000. If you would want to overwrite the behaviour of the ParameterValidator, you would create an own annotation processor with an order higher than -10000.

Caution
If you decide to overwrite tapir's behaviour, we suggest that you inherit from the default processor of the annotation in question.

If tapir cannot find an annotation processor which handles a DynamicActive annotation, the generator marks your annotated elements with an error of the form The dynamic annotation processor for … cannot be determined.

However, you might want to create an DynamicActive anotation, which has an annotation processor in some modules but not in all of them. Instead of creating an empty dummy annotation processor to avoid the error, you can also use the attribute processorRequired in the DynamicActive annotation (which is set to true by default). In tapir, we use this attribute for the SeleniumElement, because we maintain some projects, in which the SeleniumElement annotation has additional meaning and generates some code.

SeleniumElement.xtend

@Target(ElementType.FIELD)
@Retention(RUNTIME)
@DynamicActive(processorRequired = false)
public annotation SeleniumElement {
  ...
}

The following table shows all dynamic active annotations and their processor(s) in tapir. Note that some of the annotations do not have a default annotation processor.

Annotation Annotation Processor Order
BootstrapConfiguration BootstrapConfigurationProcessor -10000
ModuleConfiguration ModuleConfigurationProcessor -10000
Conditional ConditionalProcessor -10000
Configuration ConfigurationProcessor -10000
ConfigurationVariant ConfigurationVariantProcessor -10000
Include IncludeProcessor -10000
Reference ReferenceProcessor -10000
UseExtension UseExtensionProcessor -10000
Immutable ImmutableProcessor -10000
IteratedParameter ParameterValidator -10000
Parameter ParameterValidator -10000
Step StepProcessor -10000
TestClass TestClassProcessor -10000
TestClass JUnitTestClassProcessor -9000
TestSuite TestSuiteProcessor -10000
TestSuite JUnitTestSuiteProcessor -9000
CustomLabel CustomLabelProcessor -10000
JavadocGen JavadocGenProcessor -10000
Feature FeatureProcessor -10000
FeatureActivated FeatureActivatedProcessor -10000
FeatureNotActivated FeatureActivatedProcessor -10000
Action ActionProcessor -10000
SeleniumElement - -
JavaFXElement - -