This tutorial shows you how you can analyse Java annotations using jQAssistant.

Note
This tutorial has been written for version 1.3.0 of jQAssistant. In further versions of jQAssistant some aspects might change.

1. A Simple Example

In our first example we will use a Cypher query to find all classes annotated with @Foo and a second query to find all values for the name attribute of the annotation.

At first we will have a look at the source of the @Foo annotation and its usage in the class Dings`

The @Foo Annotation
@Target(ElementType.TYPE)
public @interface Foo {
     String name();
}
The Dings class
@Foo(name = "dingding")
public class Dings {
}

As we can see @Foo is a quite simple annotation with only one attribute called name. Also Dings is very straight forward.

1.1. Finding The Usage Of An Annotation

If you would like to find all usages of the annotation @Foo in your project you have to find any type with an annotation of the type you.company.project.anno.Foo. The corresponding query in Cypher looks like the query shown below.

Cypher query to find classes annotated with @Foo
MATCH (element:Type:Java)
      -[:ANNOTATED_BY]->(annotation:Java:Annotation)
      -[:OF_TYPE]->(type:Java {fqn:'you.company.project.anno.Foo'})
RETURN element, annotation, type

The result set of the query will contain three nodes: a node for the class Dings, a node for the annotation and a node for the type of the annotation.

Resultset
Figure 1. Graph representation of the result set

1.1.1. tl;dr - Why Three Nodes?

In the first moment it might be confusing that the Cypher query operates on three nodes and not two. What’s the reason?

The element node represents the annotated class and the type node is the representation for the annotation type @Foo. As @Foo is a type it can not take values. So Java must store the actual value (e.g. name = "dingsbums") somewhere. Here is where the node annotation comes into play. This node represents the concrete annotation with its concrete values found in the code. You can imagine this nodes as 'instance' of an annotation type.

1.2. Getting The Attribute Values Of An Annotation

Tiger
Figure 2. Graph with node for annotation attribute values

In case you would like to retrieve the attribute values of an annotation, you must keep in mind an attribute and its value belongs to the annotation of the annotated element and not to the type of the annotation. The type only defines the possible attributes but the concrete annotation carries the value of an annotation attribute.

For example if you would like to find all values for the name attribute of the @Foo annotation you must extend the query from the previous Cypher query. jQAssistant stores each attribute of an annotation as single node labeled with Value and linked to the annotation representing the concrete annotation with a relation labeled with HAS. Therefore we have to modify our Cypher query as shown below.

Cypher query to find classes annotated with @Foo
MATCH (element:Type:Java)
      -[:ANNOTATED_BY]->(annotation:Java:Annotation)
      -[:OF_TYPE]->(type:Java {fqn:'you.company.project.anno.Foo'}),
      (annotation)-[:HAS]->(attribute:Value {name:'name'})
RETURN attribute.value

The difference between both queries is that we extended the second with (annotation)-[:HAS]→(attribute:Value {name:'name'}). This expression takes any nodes represented by annotation and checks if it has a HAS relation to a node labeled with Value. The return clause only returns the value attribute of each matched node.

1.3. Limitations

As jQAssistant scans .class files and not Java source files you can only write concepts and constraints for annotations which are available in the generated byte code by the Java Compiler.

Java has the @java.lang.annotation.Retention annotation which allows the author of an annotation to specify the policy for retaining annotations.

At the moment exist three retention policies, provided by the enum java.lang.annotation.RetentionPolicy:

RUNTIME

Annotation is present in the class file and at runtime. Thus available to jQAssistant.

CLASS

Annotation is present in the class file and thus available to jQAssistant.

SOURCE

Annotation is only present in the source file and will be discarded by the compiler. Thus the annotation is not available to jQAssistant.

2. Resources