Community
Participate
Working Groups
Testcase: package test; import org.springframework.beans.factory.annotation.Configurable; import org.springframework.transaction.annotation.Transactional; @Configurable public class Sample { public Sample() { } @Transactional public void main(String[] args) { System.err.println("Sample"); } } Add spring.jar to classpath and spring-aspects.jar to aspectpath (Spring 2) The AJDE structure model then looks like this: sourceOfRelationship bug160236.generated<test{Sample.java[Sample~Sample relationship advised by target beanCreation sourceOfRelationship bug160236.generated<test{Sample.java[Sample~main~\[QString; relationship advised by target AnnotationTransactionAspect.class sourceOfRelationship {AnnotationTransactionAspect.class relationship advises target main sourceOfRelationship bug160236.generated<org.springframework.beans.factory.aspectj[AnnotationBeanConfigurerAspect.class (binary)}AnnotationBeanConfigurerAspect+beanCreation relationship advises target Sample The relationship for "main" advised by AnnotationTransactionAspect.class is as expected for binary weaving, but the other relationship comes out as "Sample" (the constructor) advised by beanCreation, which is a pointcut. As pointcuts are not the source of advice, this is incorrect. Expected the constructor to be advised by "AnnotationBeanConfigurerAspect.class" Unfortunately a cut-down version of the spring aspects didn't show the problem.
The reason for the wierdness is that the after returning advice in AbstractBeanConfigurerAspect is on the same line as the concrete pointcut beanCreation in the AnnotationBeanConfigurerAspect. It is this which is causing the confusion. I can now reproduce with a simplified testcase :-) One other thing - if we have source for everything (aspects and Simple class) then the structure model is: sourceOfRelationship in.one.project.generated<pkg*AbstractBeanConfigurerAspect.aj}AbstractBeanConfigurerAspect&afterReturning relationship advises target Simple sourceOfRelationship in.one.project.generated<test{Simple.java[Simple~Simple relationship advised by target afterReturning Therefore, it seems to me that in the binary case we expect the constructor to also be advised by the AbstractBeanConfigurerAspect and not the concrete AnnotationBeanConfigurerAspect.
Given the following code: --------------------------------------------------------------- public abstract aspect AbstractBeanConfigurerAspect { // advice starts on line 6 after() returning : beanCreation() { } protected abstract pointcut beanCreation(); before() : beanCreation() { } } public aspect AnnotationBeanConfigurerAspect extends AbstractBeanConfigurerAspect { // pointcut is on line 6 protected pointcut beanCreation() : initialization(*.new(..)) && !within(pkg.*); } public class Simple { public Simple() { } } ------------------------------------------------------------------ In the case when this is all in the same package, the ajde structure model is: sourceOfRelationship in.one.project.generated<pkg*AbstractBeanConfigurerAspect.aj}AbstractBeanConfigurerAspect&before!2 relationship advises target Simple sourceOfRelationship in.one.project.generated<test{Simple.java[Simple~Simple relationship advised by target afterReturning sourceOfRelationship in.one.project.generated<test{Simple.java[Simple~Simple relationship advised by target before sourceOfRelationship in.one.project.generated<pkg*AbstractBeanConfigurerAspect.aj}AbstractBeanConfigurerAspect&afterReturning relationship advises target Simple With the aspects in a jar file on the aspect path of the project containing Simple.jave, the ajde structure model is currently: sourceOfRelationship test2.generated<test{Simple.java[Simple~Simple relationship advised by target beanCreation sourceOfRelationship test2.generated<test{Simple.java[Simple~Simple relationship advised by target AnnotationBeanConfigurerAspect.class sourceOfRelationship test2.generated<pkg[AnnotationBeanConfigurerAspect.class (binary)}AnnotationBeanConfigurerAspect+beanCreation relationship advises target Simple sourceOfRelationship {AnnotationBeanConfigurerAspect.class relationship advises target Simple In other words - there are two things which need fixing: 1. Simple should be advised by AbstractBeanConfigurerAspect and not AnnotationBeanConfigurerAspect 2. Can't be advised by a pointcut (although this might be fixed as a side effect of (1).
I think the reason this bug is occuring is that the implementation of Advice.getResolvedDeclaringAspect() is wrong. According to the javadoc of the abstract method ShadowMunger.getResolvedDeclaringAspect(): /** * Returns the ResolvedType corresponding to the aspect in which this * shadowMunger is declared. This is different for deow's and advice. */ However, the implementation in Advice.java returns 'concreteAspect' (the aspect extending the aspect which defines the advice), even though Advice.getDeclaringAspect() returns the UnresolvedType corresponding to the abstract aspect in which the advice is defined. Note: The method getResolvedDeclaringAspect() is only used within the code which fills in the model for injar aspects
The fix turns out to be even more simple.....(and nicer :-)) When aspects are read in from jar files the advice is looked at and each piece of advice is allocated a declaring type. In other words, the advice knows which aspect it is declared in. In the case of advice within abstract aspects the advice knows it's declared in this abstract one. When we come to add this information to the crosscutting set we concretize each piece of advice. In this process we create a new advice object but fail to pass on the information about which type it was declared in. This is the reason why when we come to fill in the injar hierarchy the advice doesn't have a declaring type. Passing on this information in the concretization step fixes this. Consequently the whole "getResolvedDeclaringAspect" thing is redundant and can be removed. Instead, the declared type can be used both with advice and deow.
Created attachment 51925 [details] zip containing fix and testcases This zip contains the fix described above and tests: 1. pr160469-weaver.txt: apply to the weaver project. 2. pr160469-tests.txt: apply to the tests project 3. jar_1\aspects.jar: place the aspects.jar file in the tests\model\pr160469_1 directory 4. jar_2\aspects.jar: place the aspects.jar file in the tests\model\pr160469_2 directory (note jar_1 and jar_2 dirs were only created so I could attach everything within the same zip - do not create these directories in the pr160469_1 and pr160469_2 directories)
There is one final aspect to this bug which needs further thought.....with the patch in comment #5 applied the model entry for the abstract pointcut beanCreation (see comment #2) is: beanCreation() [pointcut] TEST_SANDBOX\aspects.jar!pkg\AbstractBeanConfigurerAspect.class:1: However, the line number is incorrect.
patches from comment #5 are in
Getting the pointcut location correct is more involved. Since the pointcut in the abstract aspect is a MatchesNothingPointcut we don't record any information about its location in the class file. Therefore, when we come to read it in we have no idea where in the source file the pointcut was.
For the moment it's not worth fixing the line number of the pointcut within the abstract aspect since this is only going to cause a problem if the "uses pointcut/pointcut used by" relationship is reinstated (bug 148027). With the patch committed in comment #7 I'm closing this as resolve later. This fix is in the latest aspectj dev build and will be in the next ajdt 1.4 and 1.5 dev builds.
Helen, can you please clarify what exactly need to be fixed later? I am not sure why recorded pointcut is MatchesNothingPointcut. One would expect compiler to resolve it from the super classes/aspects, since code is actually woven in.
The abstract pointcut beanCreation in AbstractBeanConfigurerAspect (see comment #2) never matches any join points because it has no body. It is the concrete pointcut within AnnonationBeanConfigurerAspect that matches. Currently when run within ajdt (or with the -emacssym option) a structure model is created that represents the crosscutting information. It is this information that AJDT uses for populating it's views. Up until the fix for bug 145963 the relationship information was only known for the current project. This had the limitation within AJDT that you weren't able to navigate to aspects that were on the aspectpath. Bug 145963 means that the model is now filled in for aspects on the aspectpath. Currently, we only fill in the information about advice, pointcuts and declare error and declare warning statements. In the case of an abstract pointcut we don't know the correct line number this was in the file since this isn't currently recorded in the class file and so can't set this piece of information correctly. However, the main user of this functionality is AJDT and AJDT only needs to know the line number to enable navigation for relationships. At the moment there is no relationship related to pointcuts and so there is no necessity to ensure the line number for the pointcut is correct. If a relationship relating to pointcuts is introduced in the future we will look at implementing what is required to ensure the line number for abstract pointcuts is correct. At the moment this is a fair amount of work (with the added complication that it could be changing the information saved in the class file) for no gain. Therefore, I closed this bug as "later" to indicate that if there is a use case for the pointcut work we will fix it when that use case becomes clear. I hope this answers your questions :-)
Well, almost. I just wonder if you can't record the line number, maybe it is at least possible to record class name that contains an applied aspect. I also wonder if there could be some kind of signature for advice that is applied at given joinpoint, so there will be no need to track down line numbers...
iplog
LATER/REMIND bugs are being automatically reopened as P5 because the LATER and REMIND resolutions are deprecated.