Package com.tngtech.archunit.core.domain
Class JavaAnnotation<OWNER extends HasDescription>
java.lang.Object
com.tngtech.archunit.core.domain.JavaAnnotation<OWNER>
- Type Parameters:
OWNER
- The type of the closest "parent" of this annotation. If this annotation is annotated on a class or member, it is that class or member. If this annotation is a member of another annotation, it is that annotation.
- All Implemented Interfaces:
HasDescription
,HasOwner<OWNER>
,HasType
@PublicAPI(usage=ACCESS)
public final class JavaAnnotation<OWNER extends HasDescription>
extends Object
implements HasType, HasOwner<OWNER>, HasDescription
Represents an imported annotation on an annotated object like a class or a method. To be
independent of the classpath, all properties of this annotation are just stored as a simple
key value pairs. I.e. if you consider
NOTE
----------
ArchUnit holds the annotation in a classpath independent representation, i.e. some types will be mapped, when the access is proxied. Consider
@MyAnnotation(name = "some name", anAttribute = 7)
class MyClass {}
this annotation will be imported storing the association
name → "some name"
anAttribute → 7
Properties will be made available via get(String)
, e.g.
myAnnotation.get("anAttribute")
will return the value 7. Since this behavior is inconvenient (loss of type safety),
there is another approach to retrieve these values, if the annotation can
be resolved on the classpath. It's then possible to access a simple proxy
MyAnnotation moreConvenient = myAnnotation.as(MyAnnotation.class);
moreConvenient.anAttribute(); // → returns 7
----------NOTE
----------
ArchUnit holds the annotation in a classpath independent representation, i.e. some types will be mapped, when the access is proxied. Consider
@SomeAnnotation(type = String.class)
class MyClass {}
Accesses to 'type' will be different for the proxied version:
someAnnotation.get("type"); // → returns JavaClass{String}
someAnnotation.as(SomeAnnotation.class).type(); // → returns String.class
-
Nested Class Summary
Modifier and TypeClassDescriptionstatic class
Default implementation ofJavaAnnotation.ParameterVisitor
implementing a no-op behavior, i.e.static interface
A Visitor (compareaccept(ParameterVisitor)
) offering possibilities to specify behavior when various types ofgetProperties()
are encountered.
The list of declared methods is exhaustive, thus any legal parameter type of anAnnotation
is represented by the respectivevisit
-method.Nested classes/interfaces inherited from interface com.tngtech.archunit.core.domain.properties.HasOwner
HasOwner.Functions, HasOwner.Predicates
Nested classes/interfaces inherited from interface com.tngtech.archunit.core.domain.properties.HasType
HasType.Functions, HasType.Predicates
-
Method Summary
Modifier and TypeMethodDescriptionvoid
accept
(JavaAnnotation.ParameterVisitor parameterVisitor) Simple implementation of the Visitor pattern (compare e.g.<A extends Annotation>
AReturns a compile safe proxied version of the respectiveJavaAnnotation
.Returns the value of the property with the given name, i.e.Returns either the element annotated with thisJavaAnnotation
(a class or member) or in case this annotation is an annotation parameter, the element annotated with an annotation that transitively declares this annotation as an annotation parameter.getExplicitlyDeclaredProperty
(String propertyName) getOwner()
Compare documentation ofOWNER
onJavaAnnotation
getType()
boolean
hasExplicitlyDeclaredProperty
(String propertyName) Returnstrue
, if and only if the value of this property has been explicitly declared within the annotation declaration.toString()
tryGetExplicitlyDeclaredProperty
(String propertyName)
-
Method Details
-
getType
-
getRawType
- Specified by:
getRawType
in interfaceHasType
-
getOwner
Compare documentation ofOWNER
onJavaAnnotation
- Specified by:
getOwner
in interfaceHasOwner<OWNER extends HasDescription>
- Returns:
- The "owner" of this object, compare
HasOwner
-
getAnnotatedElement
Returns either the element annotated with thisJavaAnnotation
(a class or member) or in case this annotation is an annotation parameter, the element annotated with an annotation that transitively declares this annotation as an annotation parameter.
Example:
For case(1)@SomeAnnotation class SomeClass {} (2) class SomeClass { @SomeAnnotation SomeField someField; } (3)@ComplexAnnotation(param = @SomeAnnotation) class SomeClass {}
(1)
the result ofsomeAnnotation.getAnnotatedElement()
would beSomeClass
, for case(2)
the result ofsomeAnnotation.getAnnotatedElement()
would besomeField
and for(3)
the result ofsomeAnnotation.getAnnotatedElement()
would also beSomeClass
, even though@SomeAnnotation
is a parameter of@ComplexAnnotation
.- Returns:
- The closest element traversing up the tree, that can be annotated
-
get
Returns the value of the property with the given name, i.e. the result of the method with the property name of the representedAnnotation
. E.g. for
the results will be@SomeAnnotation(value = "someString", types = {SomeType.class, AnotherType.class}) class SomeAnnotatedClass {}
This method will return ansomeAnnotation.get("value") → "someString" someAnnotation.get("types") → [JavaClass{SomeType}, JavaClass{AnotherType}]
explicitly declared property
, or the default value for the given property as a fallback.- Parameters:
propertyName
- The name of the annotation property, i.e. the declared method name- Returns:
- the value of the given property, where the result type is more precisely
- Class<?> → JavaClass{clazz}
- Class<?>[] → [JavaClass{clazz},...]
- Enum → JavaEnumConstant
- Enum[] → [JavaEnumConstant,...]
- Annotation → JavaAnnotation
- Annotation[] → [JavaAnnotation,...]
- anyOtherType → anyOtherType
-
hasExplicitlyDeclaredProperty
Returnstrue
, if and only if the value of this property has been explicitly declared within the annotation declaration. E.g.
The opposite is a non-explicitly declared property, e.g.@SomeAnnotation(prop = "explicitly declared") class SomeClass {}
Where the property@interface SomeAnnotationWithDefault { String prop() default "default"; } @SomeAnnotationWithDefault class SomeClass {}
prop
has the implicit default value"default"
, but no explicitly declared value.- Parameters:
propertyName
- The name of the annotation property, i.e. the declared method name- Returns:
true
, if and only if the value of this property has been explicitly declared
-
getExplicitlyDeclaredProperty
- Parameters:
propertyName
- The name of the annotation property, i.e. the declared method name- Returns:
- the same value as
get(String)
, if the property is explicitly declared (comparehasExplicitlyDeclaredProperty(String)
);
throws an exception if the property has not been explicitly declared (i.e. falls back to a default value)
-
tryGetExplicitlyDeclaredProperty
@PublicAPI(usage=ACCESS) public Optional<Object> tryGetExplicitlyDeclaredProperty(String propertyName) - Parameters:
propertyName
- The name of the annotation property, i.e. the declared method name- Returns:
- the same value as
get(String)
, if the property is explicitly declared (comparehasExplicitlyDeclaredProperty(String)
), otherwiseOptional.empty()
-
getProperties
- Returns:
- a map containing all [property → value], where each value correlates to
get(String property)
-
accept
Simple implementation of the Visitor pattern (compare e.g. https://en.wikipedia.org/wiki/Visitor_pattern).
While it is fairly convenient to analyse aJavaAnnotation
that is on the classpath (e.g. by usingas(Class)
), it is quite tedious to do so for aJavaAnnotation
not on the classpath (i.e. viagetProperties()
).
accept(ParameterVisitor)
offers an alternative by taking away traversal and casting logic when analysing potentially unknownJavaAnnotations
of different parameter structures.
Whether using this method or performing casting operations ongetProperties()
might depend on the use case. For a known annotation where only a single known parameter is relevant, a solution like
might be completely sufficient. However an analysis like "all class parameters of all annotations in packageString value = (String) knownJavaAnnotation.get("value").get()
foo.bar
should implement a certain interface" (or potentially nested annotations), this might not be an easily readable approach.accept(ParameterVisitor)
makes this use case fairly trivial:
FurthermoreunknownJavaAnnotation.accept(new DefaultParameterVisitor() { @Override public void visitClass(String propertyName, JavaClass javaClass) { // do whatever check on the class parameter javaClass } });
JavaAnnotation.ParameterVisitor
does exactly specify which cases can occur forJavaAnnotation
parameters without the need to introspect and cast the values. In case traversal into nestedJavaAnnotations
is necessary, this also becomes quite simple:
unknownJavaAnnotation.accept(new DefaultParameterVisitor() { // parameter handling logic @Override public void visitAnnotation(String propertyName, JavaAnnotation<?> nestedAnnotation) { nestedAnnotation.accept(this); } });
- Parameters:
parameterVisitor
- A visitor which allows to implement behavior for different types of annotation parameters
-
as
Returns a compile safe proxied version of the respectiveJavaAnnotation
. In other words, the result ofas(MyAnnotation.class)
will be of typeMyAnnotation
and allow property access in a compile safe manner. For this to work the respective
including all referred parameter types must be on the classpath or anAnnotation
Exception
will be thrown. Furthermore the respectiveJavaAnnotation
must actually be an import of the passed parameterannotationType
or aRuntimeException
will likely occur.- Type Parameters:
A
- The type of the importedAnnotation
backing thisJavaAnnotation
- Parameters:
annotationType
- Any type implementingAnnotation
- Returns:
- A compile safe proxy of type
JavaAnnotation
-
getDescription
- Specified by:
getDescription
in interfaceHasDescription
-
toString
-