This documentation is not maintained. Please refer to doc.castsoftware.com/technologies to find the latest updates.
Summary: this page explains how to manage annotations.

Note that the CAST Script feature described in this page is deprecated. You should instead consider using the Extension SDK to handle annotations.

Introduction

Annotations were introduced into the Java language in version 5.0. In essence they allow users to better document their source code, but they can also be used during execution and can even interact with the Java compiler via the APT (Annotation Processing Tool).

Annotations are declared exactly like interfaces - they even use the interface keyword preprended with the @ symbol:

public @interface MyAnnotation {}

Once declared, an Annotation can be used on various element types (packages, classes, enums, annotations, constructors methods, parameters, class fields and local variables). Multiple annotations can be used on the same element but the same annotation cannot be used more than once on the same element. En general, the annotation is located in front of the element:

@MyAnnotationpublic class MyClass

Why does CAST support Java Annotations?

Many new standards and frameworks use Java Annotations, for example:

  • EJB 3.0 standard
  • Web Service JSR 181
  • Spring 2.0
  • Hibernate 3.0

These annotations add new dependencies between objects and managing them is required to assess the quality of code that uses them.

How does CAST support Java Annotations?

CAST provides support for Java Annotations via its Environment Profile system. This allows you to use any of the CAST predefined Environment Profiles containing Annotation support (for example the Hibernate 3.2 Environment Profile), or to create your own Environment Profile to take into account your own Annotations.

The basic Annotation support scenario is as follows:

  • [optional] Creation of a new Environment Profile to take into account your specific Java Annotations (see also XML Annotation file structure below for more information)
  • Select either your own custom Environment Profile or select a CAST predefined profile if you are using a specific framework that uses Annotations (e.g.: Hibernate 3.2).
  • Analysis is run - when the analyzer detects an Annotation in your source code as defined in the selected Environment Profile the source file and annotation are added to an "annotation list" - one list is created for each Annotation Group that is defined in the selected Environment Profile.
  • At the end of the J2EE analysis, this "annotation list" will result in the creation of a set of auto-generated XML Annotation files (one file for each Annotation group defined in the selected Environment Profile) - these files can be saved to a hard drive or network location if required (see the debug options when you use the Run analysis only option - Keep Generated CAST Scripts from XML and Annotations).
  • The analyzer then uses the XML Query/XQuery files associated to the Java Annotation groups (as defined in the Environment Profile) to extract information from these XML Annotation files and create objects representing Annotations that can be saved into the CAST Analysis Service and then exploited via any of CAST's end-user applications.

XML Annotation file structure

CAST has designed its support of Java Annotations to be flexible and thus customizable. As a result, the following section describes how the auto-generated XML Annotation files are structured so that you can (if necessary) write a new XML Query file/XQuery (that can be associated to your JEE Environment Profile) to manage annotations not supported by CAST via a predefined Environment Profile (e.g. Hibernate 3.2 etc.). You can see some guidelines on creating XML Query/XQuery files in Manage XML configuration files. If you want to see the XML Annotation files, remember to select the appropriate debug option when you use the Run analysis only option (Keep Generated CAST Scripts from XML and Annotations).

Below is an example of an XML Annotation file that was automatically generated during the analysis:

<?xml version="1.0" encoding="iso-8859-1" ?>
	<decls>
    	<decl metatype="object_type" >
        	<loc 
      			file="file_full_path" sLine="1" sCol="1" eLine="50" eCol="1"/>
      			<name>
            		< ![CDATA[object_name]]>
      			</name>
        		<decl metatype="object_type">
      				<name>
                		< ![CDATA[object_name]]>
      				</name>
           		<type>   
      				< ![CDATA[type_or_object_return_type]]>
            	</type>
      			<anno>
                	<name>  
      					< ![CDATA[full_annotation_name]]>
                	</name>
      				<loc [file="file_full_path"] sLine="10" sCol="30" eLine="12" eCol="30"/> 
      				<mem>
                    	<name>  
      						< ![CDATA[member_name]]>
                    	</name>
     					<loc [file="file_full_path"] sLine="13" sCol="30" eLine="13" eCol="30"/>
      					<val>
                        	< ![CDATA["element_value1"]]>
      					</val>
                    	<val>
      						< ![CDATA["element_value2"]]>
     					</val>
                	</mem>
      			</anno>
            	<param pos="1">
      				<name>
                    	< ![CDATA["par1"]]> 
      				</name>
           		</param>
      		</decl>
    	</decl>
    	<decl 
    		metatype="object_type">
        	<name>  
      			< ![CDATA[object_name]]>
        	</name>
      		...
    	</decl>
	</decls>
</xml>

The following key will help understand this file:

  • decl: tag describing each source code object that will be created in the Analysis Service
    • decl.metatype: metamodel name of the object type. This allows you to filter on object type name in your XML Query file/XQuery file
  • decl/name: tag containing a CDATA section containing the object name. For a class or interface, this is the object's qualified name, in all other cases this is the simple name
  • decl/type: Only displayed if the object is a method or class field. If it is a method, it will indicate the method's return type. If it is a field, this will indicate its type. A CDATA section will contain the type's qualified name.
  • loc: tag used to indicate the position of elements in the source code
    • loc.file: file's full path. All the child elements of the element that is defined with loc will inherit this location. If the child element is located in a different file, then this element will have its own loc.file.
    • loc.sLine, loc.sCol, loc.eLine, loc.eCol: absolute positions (with regard to the start if the file).
  • decl/anno: tag representing an instance of an annotation applied to the object represented by the decl tag.
  • anno/name: tag containing a CDATA section containing the qualified name of the annotation.
  • anno/mem: annotation member
    • mem/loc.file: optional - useful if it is a default value. In this case, the member file points to the annotation type file. Also useful for managing the @Inherited annotation. In this case, the file is the file containing the super class where the annotation was instantiated in the source code.
  • mem/name: tag containing a CDATA section containing the simple name of the annotation member
  • mem/val: tag containing a CDATA section containing a value used in the annotation member
    • Under a "mem" tag, several "val" can exist, e.g. for an array
    • "val" is a child element of "mem" and not an attribute, because array's can be the values of a member. In addition, annotations or annotation arrays may exist.
    • If the member type is an "enum", the full name of the enum Item will be displayed as used in the annotation.
    • If the value is an expression, it is displayed "as is". For example, for a String (there is no expression evaluator):
    <val> < ![CDATA["toto" + (5/4) + "tata"]] </val>
  • decl/param: parameter of the object represented by the "decl" tag.
    • param.pos: an annotated parameter has its position "pos" in the signature as an attribute
  • param/name: tag containing a CDATA section containing the nam of the parameter - required for WSDL.
  • When generated, the XML Annotation files do not contain any tab formatting - this is to reduce the size of the files. For debugging purposes, please use a text editor that can automatically format tabs.
  • To save space, not all declarations have their full name. A qualified name is only indicated for types. In addition, when recursively examining the declaration tree, it can be easily reconstituted.
  • Part of this text is adapted from: http://adiguba.developpez.com/tutoriels/java/tiger/annotations/
  • The structure of the generated XML Annotation files may change in future CAST releases. As such your XML Query file/XQuery file may need updating if you migrate to a new CAST version.
  • The XML Query file can create only specific types and resolve names against specific object types. This is why in this current release, it is not possible to create a Web Service object from an annotation, but you can create a generic XML Object from the Web Service annotation. The list of types that can be created are defined in the XML schema located in CAST_INSTALL_DIR\configuration\J2EE\schemas\cast-config.xsd.

Annotation group

Annotations defined in Java files and annotated objects are stored in the JEE Analyzer memory and can be queried afterward through CAST Script.

Create an annotation group

To instruct the J2EE Analyzer to save these annotations, you must:

  1. Define an Environment Profile (if it doesn't already exist) for the framework you want to handle. For example, a profile to manage TestNG annotations (http://testng.org/).
  2. Define an annotation Group in the Environment Profile
  3. Define the list of annotations to handle
  4. Select the Analysis Method: the recommended method is CAST Script, the other one will be removed in a future version.

Which annotations to take into account?

This depends on:

  • The quality rules you want to create. If a quality rule depends on a specific property, then you must add this property to the object you will create.
  • Links between objects: to ensure navigation in CAST Enlighten and a correct Function Point result, you need to manage links from modules referenced through annotations. This is the case for example for links from Java classes to JPA entities and from JPA Entities to database tables.

Which annotation should be put in an annotation group?

An annotation group must:

  • Reference annotations that belong to the same semantic, for example: JPA annotations
  • If you use the new parsing method (CAST Script), you just have to reference annotation you want to manage. Independently of which annotation you add in this list, all annotations used in your code will still be queried by the CAST Script. The only consequence of missing one is a warning during the analysis to inform you that a specific annotation is not managed.

You will now need to customize the CAST Script.

Handling Annotations with CAST Script

The way to handle Java annotations with CAST Script is based on a new set of native functions:

  • native list(symbol) getSymbolsAnnotatedWith( symbol annotationType, string metatypeOrCategory );
  • native list(symbol) getSymbolsAnnotatedWith( symbol annotationType, list(string) metatypeOrCategories );
  • list(symbol) getSymbolsAnnotatedWith( string annotationFullName, string metatypeOrCategory )
  • list(symbol) getSymbolsAnnotatedWith( string annotationFullName, list(string) metatypeOrCategories )
  • symbol getAnnotationParameter( symbol annotation, string name )
  • native boolean hasAnnotation( symbol object,string annotation );
  • native list(symbol) getAnnotations( symbol object );
  • native boolean isDefaultParameter( symbol annotationParameter );
  • string getParameterStringFromAnnotation(symbol object,string annotationName,string parameterName)

with a set of string manipulation functions:

  • native string concat(string word_1,string word_2);
  • native string substring(string word, int index_begin, int length);
  • native string substring(string word, int index_begin);
  • native int getLength(string word);
  • native string toLower(string word);
  • native string toUpper(string word);
  • native int getFirstIndex(string word,string substring);
  • native string substringMatch(string word,string regexp);
  • native string toString(boolean value);
  • native string toString(int value);


Defining a CAST Script to manage a set of annotation would have the following body:

/* for all class of methods that have a specific annotation do... */
list(symbol) myClasses = getSymbolsAnnotatedWith( "myAnnotation" , JV_CLASS );
foreach( symbol class in myClasses) {
   /* create object and/or link and/or add properties */
   ...
}

Report to the Help to get the full description of native functions.

Sample:

Let's manage annotations from the following file Bid.java:


...
if you want to create an Hibernate Entity named Bid in the KB with associated links from the class and to the database table, we will use the following functions in a file located in:

<Custom CAST Script Library Path>\Custom\JEE\JPAAnnotations.castscript

/* module declaration */
module Custom.JEE.JPAAnnotations;

/* import declarations */
use Core.ConstantsMetamodel;
use Core.Log;
use Core.JEE.Annotations;
use Core.JEE.JEE;

/* creation of an Entity whose implementation class is entityClass and
 * the annotation fullname is entityAnnotation, create the link with the
 * class and the table and return the entity symbol that has been created
 */
symbol createEntity(symbol entityClass, string entityAnnotation) {
   /* 1. first we must find the name of the entity */
   /* 1.1 get the 'name' property value of @Entity annotation if exists */
   string entityName = getParameterStringFromAnnotation(entityClass,
                             entityAnnotation,"name");
   /* 1.2 if the annotation doesn't contains the entity name property,
      then the class name is used */
   if (entityName == "" || entityName == null) {
      entityName = getStringProperty(entityClass, identification_name );
   }

   /* 2. The entity parent in the object tree is the Java class file,
      so we must find this file */
   symbol entityFile = getSymbolUniqueParent(entityClass);

   /* 3. Creation of the entity */
   symbol jpaEntity = findOrCreateSymbol(entityName, JPA_ENTITY,
                          entityFile);

   /* 4. Creation of a link from the Java class
      to the Entity */
   createLink (entityClass, jpaEntity, useLink );

   /* 5. Creation of a link from the Entity to the table */
   /* 5.1 find the 'name' property value of @Table annotation if exists */
   string entityTable = getParameterStringFromAnnotation(entityClass,
                            "javax.persistence.Table","name");
   /* 5.2 if the annotation doesn't exist the entity table name,
      is the class name */
   if ((entityTable == "" || entityTable == null) {
      entityTable = entityName;
   }
   /* 5.3 get the symbol from the table name */
   symbol serverObject = findUniqueSymbol(entityTable, GROUP_SqlObject);
   /* 5.4 create the link */
   createLink (jpaEntity, serverObject, useLink );

   /* 6 return the entity */
   return jpaEntity;
}

void createAllEntities() {
    /* to manage Entities */
    list(symbol) myEntityClasses = getSymbolsAnnotatedWith(
                                "javax.persistence.Entity", JV_CLASS );
    foreach( symbol entityClass1 in myEntityClasses) {
       symbol entity = createEntity(entityClass1,
                       "javax.persistence.Entity");
    }

    /* to manage MappedSuperclass */
    myEntityClasses = getSymbolsAnnotatedWith(
                     "javax.persistence.MappedSuperClass" , JV_CLASS );
    foreach( symbol entityClass in myEntityClasses) {
       symbol entity = createEntity(entityClass,
                       "javax.persistence.MappedSuperClass");
    }
}

And we will reference the following file in the Environment Profile <Custom CAST Script Library Path>\Custom\JEE\JPA.castscript

/* module declaration */
module Custom.JEE.JPA;

/* import declarations */
use Custom.JEE.JPAAnnotations;

/* entities creation */
createAllEntities()
  • In this sample, only the interface 'javax.persistence.Entity' is required for the annotation @Entity.
  • javax.persistence.MappedSuperclass' has been added to manage the more general case where the annotation @MappedSuperclass is used.
  • <Custom CAST Script Library Path> directory is defined though the menu Technology > J2EE > Platform Setting > CAST Script Library Directory

Managing SQL Queries embedded in annotations

To manage SQL annotation embedded in Java annotations, you just have to create a CAST Script that get the annotation value (the same as explained in the sample Handling Annotations with CAST Script - see above) and then call the CAST Script function analyzeDBQuery as explained in Handling Annotations with CAST Script - see above. Write the CAST Script function that will create the Cast_SQL_NamedQuery object except that you have to use the analyzeDBQuery with the signature symbol analyzeDBQuery(string queryType, string queryName, string dbRequest, symbol queryParent) to set the parent of the query objet to the Java class, method or attribute depending on which is the object type the annotation is associated to.

Some CAST Script tips

Notion of parents: how to navigate in the memory representation of Java and JSP objects?
When using CAST Scripts functions that have a parameter "parent", how to know what is a parent of a specific object?

This notion of parent and children is the same that is displayed in Enlighten Object Tree. You can see for example, that a Java Class is the child of a Java File.

There is only one exception to this rule: the Java annotations. Java annotations applied on a class are not represented in Enlighten (there is only an annotation object type but not the annotation applied on the class, method, field...). So, what you must know is that if you want for example the list of annotations used on a class, method or field, you must use findUniqueSymbol with the annotation fullname, the type = CAST_Java_AnnotationType and use the class, method or field as the parent.

In the same way, annotation parameters are children of annotations.