Skip to main content
Jump to: navigation, search

Developer's guide to building tools on top of AJDT and AspectJ

Revision as of 13:23, 10 January 2007 by (Talk | contribs)

This page is intended to aid anyone developing tools to extend or work with AJDT/AspectJ. Please contribute to this page with any relevant information, such as example code using the AJDT and/or AspectJ APIs.

Obtaining crosscutting relationship information from AJDT

(the following is derived from a post to the AJDT newsgroup on 26/10/2006)

If you're developing an eclipse plugin and require access to crosscutting information whenever a project is built, you can register a listener with AJDT. Your plug-in will need to depend on org.eclipse.ajdt.core, org.eclipse.core.resources and org.eclipse.jdt.core. In the org.eclipse.ajdt.core plug-in there is an IAdviceChangedListener interface with a single adviceChanged() method.

Register this with the AJBuilder class like this (in your plug-in's start() method for example):

   AJBuilder.addAdviceListener(new MyAdviceListener()); 

Currently (AJDT 1.4) this is called after every build of an AspectJ project (i.e. every *potential* advice change). In a future release this may be optimized to be only called if the advice has actually changed. AJDT/UI uses this mechanism to update the orange arrow image decorator.

Crosscutting information can then be obtained from the AJModel class. Here's an example:

 public class MyAdviceListener implements IAdviceChangedListener { 
   public void adviceChanged() { 
       IProject project = AspectJPlugin.getDefault() 
       System.out.println("build detected for project: " + project); 
       AJRelationshipType[] relsTypes = AJRelationshipManager 
       List rels = AJModel.getInstance().getAllRelationships( 
               project, relsTypes); 
       for (Iterator iter = rels.iterator(); iter.hasNext();) { 
           AJRelationship ajrel = (AJRelationship); 
           System.out.println("Relationship: " 
                   + ajrel.getSource().getElementName() + " " 
                   + ajrel.getRelationship().getDisplayName() + " " 
                   + ajrel.getTarget().getElementName()); 

For the "TJP Example" project (File > New > Other > AspectJ > AspectJ Examples), this prints:

 build detected for project: P/TJP Example 
 Relationship: around advises main 
 Relationship: around advises foo 
 Relationship: around advises bar 
 Relationship: bar advised by around 
 Relationship: foo advised by around 
 Relationship: main advised by around 

As you can see, you get the relationship in both directions. See AJRelationshipManager for the full list of relationships, so you can just ask for the relationship types you're interested in.

AJRelationship.getSource() and getTarget() return instances of IJavaElement so you can obtain further information from that, such as the parent or underlying resource.

Compilation Units in AJDT

JDT creates compilation units (instances of ICompilationUnit) for .java files. AJDT creates compilation units for .aj files, which are instances of AJCompilationUnit (which implements ICompilationUnit). The class AJCompilationUnitManager (in the org.eclipse.ajdt.core plug-in) contains some useful methods relating to this, such as:

 public AJCompilationUnit getAJCompilationUnit(IFile file)

From an AJCompilationUnit you can obtain various structural information such as getAllTypes(). The primary type for ".aj" files is typically an aspect, which is represented by the AspectElement class, which contains aspect-specific methods such as getPointcuts() and getAdvice(). These return further aspect-specific elements such as PointcutElement and AdviceElement.

Since AJDT 1.4 for Eclipse 3.2, we register the ".aj" file extension as containing "Java-like" source code. One side-effect of this is that JDT creates its own compilation unit for a .aj file, in addition to the one created by AJDT. This is usually empty, as JDT doesn't understand aspects. If you obtain a compilation unit for a .aj file, you may therefore need to ensure it is an AJCompilationUnit - the method AJCompilationUnitManager.mapToAJCompilationUnit() can be used for this. Also, in order to distinguish the two compilation units, they have different working copy owners (and the JDT ones are filtered from the package explorer). This means for example that IType.resolveType(String) won't work for aspects - instead you need to use the two arg version, IType.resolveType(String, WorkingCopyOwner), specifying AJDT's working copy owner:


Using the AspectJ AST parser

Basic example, taken from bug 88861

 import java.util.*;
 public class Program {
   public static void main(String []argv) {
     ASTParser parser = ASTParser.newParser(AST.JLS2);
     parser.setCompilerOptions(new HashMap());
     CompilationUnit cu2 = (CompilationUnit) parser.createAST(null);
     AjNaiveASTFlattener visitor = new AjNaiveASTFlattener();

Compile the above and run it:

 java Program "public aspect X { pointcut p(): call(* *(..));}"

then it prints:

 public aspect X {
    pointcut p():call(* *(..));

See also bug 110465: Continue AST work

Known limitations, bugs, and outstanding issues

Limitation: There is currently no AST support for resolving type bindings:

Back to the top