- Notifications
You must be signed in to change notification settings - Fork2
Upgraded fork of hickory (updated to Java 11 with module-info and new features)
License
avaje/avaje-prisms
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
Fork of the legendaryhickory annotation processor. Hickory has served pretty well since it was created in 2010, but it's unmaintained and doesn't have module support.
When writing annotation processors the two conventional mechanisms to access the annotations are both awkward.Element.getAnnotation()
can throw Exceptions if the annotation or its members are not semantically correct, and it can also fail to work on some modular projects. (This is one the reasons why<annotationProcessorPaths>
is required for modular projects but it is seriously limited and technically not correct either (SeeMCOMPILER-412) Moreover, when calling a member with aClass
return type, you need to catch an exception to extract theTypeMirror
.
On the other hand,AnnotationMirror
andAnnotationValue
do a good job of modeling both correct and incorrect annotations, but provide no simple mechanism to determine whether it is correct or incorrect, and provide no convenient functionality to access the member values in a simple type-specific way. WhileAnnotationMirror
andAnnotationValue
provide an ideal mechanism for dealing with unknown annotations, they are inconvenient for reading member values from known annotations.
A Prism provides a solution to this problem by combining the advantages of the pure reflective model ofAnnotationMirror
and the runtime (real) model provided by Element.getAnnotation(), hence the term Prism to capture this idea of partial reflection.
A prism has the same member methods as the annotation except that the return types are translated from runtime types to compile time types as follows...
- Primitive members return their equivalent wrapper class in the prism.
- Class members return a TypeMirror from the mirror API.
- Enum members return a String being the name of the enum constant (because the constant value in the mirror API might not match those available in the runtime it cannot consistently return the appropriate enum).
- String members return Strings.
- Annotation members return a Prism of the annotation. If a prism for that annotation is generated from the same @GeneratePrisms annotation as the prism that uses it, then an instance of that prism will be returned. Otherwise, a Prism for that annotation is supplied as an inner class of the dependant Prism. the name of which is the simple name of the referenced annotation type.
- Array members return a List where X is the appropriate prism mapping of the array component as above.
<dependency> <groupId>io.avaje</groupId> <artifactId>avaje-prisms</artifactId> <version>${avaje.prism.version}</version> <optional>true</optional> <scope>provided</scope></dependency>
When working with Java modules you need to add prisms as a static dependency.
modulemy.processor {requiresstaticio.avaje.prisms;}
2. In your AP's pom.xml, replace<compilerArgument>-proc:none</compilerArgument>
with this annotation processor
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <annotationProcessorPaths> <path> <groupId>io.avaje</groupId> <artifactId>avaje-prisms</artifactId> <version>${avaje.prism.version}</version> </path> </annotationProcessorPaths> </configuration></plugin>
This ensures that only the prism generator will run at build time.
// package-info.java@GeneratePrism(MyExampleAnnotation.class)//@GenerateUtils optionally can add this to generate a helper classpackageorg.example
voidsomeFunction(Elementelement) {MyExampleAnnotationPrismexampleAnnotation =MyExampleAnnotationPrism.getInstanceOn(element);//can get the original annotation type as a stringStringannotationQualifiedType =MyExampleAnnotationPrism.PRISM_TYPE//can easily retrieve the annotation values as if the annotation was present on the classpath.exampleAnnotation.getValue() ... }
Avaje prisms will try to detect your processor class and register an entry toMETA-INF/services/javax.annotation.processing.Processor
after compilation. Doing this means you can omit the compiler plugin configuration. (<compilerArgument>-proc:none</compilerArgument>
and step 2 in the how to use section)
Services entries will be added if a concrete processor class has any of the following annotations:
- Any avaje prism annotation
@SupportedAnnotationTypes
@SupportedOptions
@SupportedSourceVersion
If you add the annotation,this Helper Class will be generated into your project to allow you to access the processing environment statically from anywhere.
To initialize/cleanup the generatedAPContext
do the below:
@GenerateAPContextpublicfinalclassMyProcessorextendsAbstractProcessor {@Overridepublicsynchronizedvoidinit(ProcessingEnvironmentenv) {super.init(env);APContext.init(env); }@Overridepublicbooleanprocess(Set<?extendsTypeElement>tes,RoundEnvironmentrenv) {if (renv.processingOver()) {APContext.clear();returnfalse; }//do whatever processing you need }}
- Upgrades from JDK 6 to 11
- Adds modular support via module-info
@GeneratedPrism
is now repeatable- Can choose what classes the generated Prisms inherit.
- Generates an
isPresent
method to check if an element has the target annotation easily - Generates
Optional
factory methods - Generates a
getAllInstances
method to retrieve a list of prisms from an element (@Repeatable
annotations only) - Generates a
getAllOnMetaAnnotations
method to retrieve a list of prisms from an element's annotations (Meta annotations only) - Exposes the fully qualified type of the target annotation as a string.
getInstance
returns null instead of throwing exceptions when the provided mirror doesn't match the prism target- null annotation array values are returned as empty lists
- META-INF/services generation
About
Upgraded fork of hickory (updated to Java 11 with module-info and new features)