[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [aspectj-users] Advice on Constructors With Subclasses

Hi James,
nice to hear my code was somewhat useful.

Have you seen the comments on your feature request?

Simone

James Elliott wrote:
> I played with Simone's code a bit, and it does seem to work as described.
>
> Here's the solution I came up with for when the constructor call is
> made within a constructor call.
>
> This solution works assuming that the only places where A or it's
> subclasses are instantiated within the constructor of A or it's
> subclasses are in code that can be woven, which, for my project, is a
> safe assumption.
>
> I made the class abstract so that it can be easily reused whenever
> this pattern is appropriate.
>
> I don't like having the getMyClass() method, but I don't know of a
> good way to get the generic type without it.
>
> I am also caching the return value from isAssignableFrom, since this
> call appears to be relatively expensive in some versions of java.
>
> It's still a bit of a hack, but it seems to fulfill my needs.
>
> public abstract aspect InitializationAspect<T> {
> 	/* Cache to avoid reflective calls */
> 	private Map<String, Boolean> isAssignableMap = new HashMap<String, Boolean>();
> 	
> 	/**
> 	 * Returns the class highest in the hierarchy.  Should be T.
> 	 */
> 	protected abstract Class<T> getMyClass();
> 	
> 	/**
> 	 * The Advice to perform after an object has been instantiated.
> 	 * @param t The object that was created.
> 	 */
> 	protected abstract void myAdvice(T t);
> 	
> 	/**
> 	 * Checks to make sure that the constructor that is executing
> 	 * is the type of the object to be created (i.e. lowest on the stack)
> 	 * and calls myAdvice() if it is. Does nothing if not.
> 	 * @param t The object that was created
> 	 */
> 	after(T t) : execution(T+.new(..)) && this(t)  {
> 		if (isLastConstructorInChain(getMyClass())) {
> 			myAdvice(t);
> 		}
> 	}
> 	
> 	/**
> 	 * Captures any calls to create a new object of type T or it's subtypes
> 	 * that happen within type T or it's subtypes, and calls myAdvice().
> 	 */
> 	after() returning(T t): call(T+.new()) && withincode(T+.new(..)) {
> 		myAdvice(t);
> 	}
> 	
> 	/**
> 	 * Returns true if a class' constructor the lowest method call in a
> 	 * chain of constructor calls.  If it isn't, return true if the next lowest
> 	 * call is not type T or a subclass of type T, false otherwise.
> 	 * @param clazz The class to look for.
> 	 */
> 	public boolean isLastConstructorInChain(Class<?> clazz) {
> 		StackTraceElement[] stackTrace =
> 			Thread.currentThread().getStackTrace();
> 		
> 		// find the first constructor, cause there are a few AspectJ
> internal calls before it
> 		int acpos = 0;
> 		while (acpos < stackTrace.length &&
> 				!stackTrace[acpos].getMethodName().equals("<init>")) {
> 			acpos++;
> 		}
> 		// Check if we run out, should never happen
> 		if (acpos >= stackTrace.length) {
> 			return false;
> 		}
> 		// Now we have the last call to <init>
> 		// if the following one is not a constructor (or is not present),
> 		// we can skip all the checks and return true
> 		if (acpos + 1 == stackTrace.length ||
> 				!stackTrace[acpos + 1].getMethodName().equals("<init>")) {
> 			return true;	
> 		}
> 		// Otherwise we have to check it the next constructor in the
> 		// chain is a proper subclass of the current class
> 		String callingClass = stackTrace[acpos + 1].getClassName();
> 		
> 		Boolean isAssignable = isAssignableMap.get(callingClass);
> 		
> 		if(isAssignable == null) {
> 			Class<?> forname = null;
> 			try {
> 				forname = Class.forName(callingClass);
> 			}
> 			catch (ClassNotFoundException e) {
> 				e.printStackTrace();
> 				isAssignable = false;
> 			}
> 			isAssignable = !clazz.isAssignableFrom(forname);
> 			
> 			isAssignableMap.put(callingClass, isAssignable);
> 		}
> 		return isAssignable;
> 	}
> }
>
> public aspect AAspect extends InitializationAspect<A> {
> 	protected Class<A> getMyClass() {
> 		return A.class;
> 	}
> 	
> 	protected void myAdvice(A a) {
> 		System.out.println("Done:" + a.getClass());
> 	}
> }
> _______________________________________________
> aspectj-users mailing list
> aspectj-users@xxxxxxxxxxx
> https://dev.eclipse.org/mailman/listinfo/aspectj-users
>   


-- 
Simone Gianni
http://www.simonegianni.it/
CEO Semeru s.r.l.
Apache Committer