Consider the AspectJ program in the appendix for checking the object form of the Law of Demeter. It is incomplete in that it deals only with immediate parts. Now we want to extend it to deal with the other rules. Therefore we add the following aspect TargetBinStack which serves as superaspect of several subaspects: package lawOfDemeter; import org.aspectj.lang.*; import java.util.*; /** * The BinStack aspect is part of a Law of Demeter Checker - a set of * classes and aspects that verify a given program does not violate * the Law of Demeter. This aspect addresses the concern of storing a stack of * bins that contain the targets being examined * * @author David H. Lorenz * @author Modifications made by Paul Freeman */ abstract aspect TargetBinStack extends Supplier { /** * Used in debugging print statements. * @return Returns a string describing what this bin contains. */ abstract String contains(); /** * This is the pointcut used by the before and after advice to stack the * target bins. */ abstract pointcut EventToStack(); /** * This is the pointcut used by the around advice to gather the objects. */ abstract pointcut EventToGather(); /** * The method that fires to the implementing aspect before the EventToGather * proceeds, signalling gathering within the implementing aspect to take place. */ abstract void gatherBefore(JoinPoint thisJoinPoint); /** * The method that fires to the implementing aspect before the EventToGather * proceeds, signalling gathering within the implementing aspect to take place. */ abstract void gatherAfter(JoinPoint thisJoinPoint, Object returnValue); /** * Advice that maintains a stack of targets. */ Stack targetStack = new Stack(); Object around(): // keep track of arguments EventToStack(){ // before a method executes, we store the current stack of targets targetStack.push(targets); // and initialize a new stack of targets targets = new HashMap(); Object returnVal = proceed(); // after the method executes, we restore the previous stack of targets targets = (HashMap)targetStack.pop(); return returnVal; } /** * Fires the gather method to the implementing aspect. The advice must occur * here in the implementing class so that it can be ordered correctly with the * gathering advice. If the gathering advice was implemented in the subclass, * it would fire before the super classes advice. The dominates keyword will not * override this. */ Object around(): EventToGather(){ gatherBefore(thisJoinPoint); Object returnValue = proceed(); gatherAfter(thisJoinPoint, returnValue); return returnValue; } /** * Prints the objects in the current bin. * Used for debugging. */ public void printTopBin(){ System.out.println("== TOP "+contains()+" =="); printHashMap(targets); System.out.println("======================"); } /** * Prints each bin in the stack. * Used for debugging. */ public void printAllBins(){ System.out.println("== ALL "+contains()+" =="); // targetStack contains one empty bin by default so start at size - 1 for(int i = targetStack.size() - 1; i >= 0; i--){ System.out.println("-- bin " + i + " --"); if(i == 0){printHashMap(targets);} else{printHashMap((HashMap)targetStack.elementAt(i - 1));} System.out.println("-------------------"); } System.out.println("======================"); } } // end of program ============================================================ Now we focus on the two abstract pointcuts and the two abstract methods in TargetBinStack: abstract pointcut EventToStack(); abstract pointcut EventToGather(); abstract void gatherBefore(JoinPoint thisJoinPoint); abstract void gatherAfter(JoinPoint thisJoinPoint, Object returnValue); Below are the concrete implementations in three subaspects to complete the implementation of the Law of Demeter checker: Find the UNKNOWNs. public aspect ArgumentBin extends TargetBinStack { pointcut EventToStack(): Any.Execution(); pointcut EventToGather(): Any.Execution(); void gatherBefore(JoinPoint thisJoinPoint){ // store the arguments of the method addAll(thisJoinPoint.getArgs(), argument + at(thisJoinPoint)); // arguments include this/self - store the object currently executing add(thisJoinPoint.getThis(), receiver + at(thisJoinPoint)); } void gatherAfter(JoinPoint thisJoinPoint, Object returnValue){ // do nothing } ... } public aspect LocallyConstructedBin extends TargetBinStack { pointcut EventToStack(): Any.Execution(); pointcut EventToGather(): Any.ConstructorCall(); void gatherBefore(JoinPoint thisJoinPoint){ // do nothing } void gatherAfter(JoinPoint thisJoinPoint, Object newLocalObj){ add(newLocalObj, local + at(thisJoinPoint)); } ... } public aspect ReturnValueBin extends TargetBinStack { pointcut EventToStack(): Any.Execution(); pointcut EventToGather(): Any.MethodCall(); void gatherBefore(JoinPoint thisJoinPoint){ // do nothing } void gatherAfter(JoinPoint thisJoinPoint, Object returnVal){ if(returnVal != null){ if(thisJoinPoint.getThis() == thisJoinPoint.getTarget()){ add(returnVal, local + JPUtil.at(thisJoinPoint)); } } } ... }