Note
|
This project has moved to MP GraphQL |
Instead of SuperHero.class.getAnnotation(Entity.class)
, use Annotations.on(SuperHero.class).get(Entity.class)
and you’ll get some very powerful features described below. This works also for fields and methods; simply use Annotations.onField
or Annotations.onMethod
.
Fields and methods don’t have to be declared directly on the target class or interface, but can be inherited from some super class or interface. All annotations work as if the field was on the sub type.
If there is a Jandex index file, all annotations will be read from there.
A Jandex file is advisable but optional, i.e. if there is no Jandex file, Power-Annotations will fall back to scan the classpath with JDK reflection, slowing down startup time. As this also means that a lot of classes from all dependencies have to be scanned, this can have a severe performance impact. If you want to stay dynamic but exclude some dependencies, you can do so by adding a file META-INF/jandex.properties
with a property exclude
containing a space-delimited list of artifactId:groupId
. See implementation/src/main/resources/META-INF/jandex.properties
.
When annotating a super class or interface, the annotation is valid also for the sub class or interface. This is also true for annotations on overridden or implemented methods.
In Java reflection, this only works for super classes and only if the annotation is annotated as @Inherited
. As this generally violates the LSP, power-annotations always resolves these annotations. We may add a mechanism to not inherit annotations later, if the need actually arises.
The simplest use-case for Stereotypes is renaming annotations, e.g. @Property
instead of @JsonbProperty
(assuming your JBON-B implementation supported Power Annotations).
@Retention(RUNTIME)
@Stereotype
@JsonbProperty
public @interface Property {}
It gets much more interesting, when you add more annotations from other (supporting) frameworks to your stereotype, e.g. @XmlAttribute
from JAX-B. Now you have one annotation instead of two with both having the same semantics.
Properly used, stereotypes are shortcuts describing the role the annotated element has; functionally as well as a documentation.
This is exactly what CDI-Stereotypes do, but not restricted to CDI, i.e. the annotations used by any framework that supports Power Annotations can be used with stereotypes. We have our own Stereotype
class; but as we don’t want to depend on CDI and still not exclude CDI, any annotation named Stereotype
will work.
This is a very common pattern: annotations on a class are considered as a fallback for member annotations (i.e. on fields or methods), if
-
the member is not annotated with the same type or the annotation is repeatable, and
-
the annotation is annotated to be an explicitly allowed
@Target
forFIELD
/METHOD
.
Say you have a class you want to add annotations to, but you can’t; e.g., because it’s a class from some library or even from the JDK. You can create your own class (or interface) and annotate it as @MixinFor
the target class. The annotations you put on your mixin class will work as if they were on the target class (if your framework supports Power Annotations).
This also works for annotations: say we’re developing an application packed with annotations from JPA, which doesn’t support mixins (yet). The application also uses a library that supports mixins but doesn’t know about JPA, e.g. a future MP GraphQL. We want all JPA @Id
annotations to be recognized as synonyms for GraphQL @Id
annotations. We could create a simple mixin for the JPA annotation:
@MixinFor(javax.persistence.Id.class)
@org.eclipse.microprofile.graphql.Id
public class PersistenceIdMixin {}
Voila! MP GraphQL would work as if all JPA @Id
annotations were it’s own.
Note
|
Mixins are a very powerful kind of magic: use them with caution and only when strictly necessary. Otherwise, the readers of your code will have a hard time to find out why something behaves as if an annotation was there, but it’s clearly not. If you can, use Stereotypes instead. |