@@ -13,13 +13,14 @@ package org.aspectj.lang; | |||
import java.lang.reflect.Method; | |||
import java.lang.reflect.Modifier; | |||
import java.lang.reflect.InvocationTargetException; | |||
/** | |||
* Handles generic aspectOf method when those are not available in the aspects but added later on | |||
* thru load time weaving. | |||
* <p/> | |||
* Aspects.aspectOf(..) is doing reflective calls to the aspect aspectOf, so for better performance | |||
* consider using preparation of the aspects. | |||
* consider using ajc compilation of the aspects and using them as a binary dependancies in your project. | |||
* | |||
* @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a> | |||
*/ | |||
@@ -27,11 +28,13 @@ public class Aspects { | |||
private final static Class[] EMPTY_CLASS_ARRAY = new Class[0]; | |||
private final static Class[] PEROBJECT_CLASS_ARRAY = new Class[]{Object.class}; | |||
private final static Class[] PERTYPEWITHIN_CLASS_ARRAY = new Class[]{Class.class}; | |||
private final static Object[] EMPTY_OBJECT_ARRAY = new Object[0]; | |||
private final static String ASPECTOF = "aspectOf"; | |||
private final static String HASASPECT = "hasAspect"; | |||
/** | |||
* Returns the singleton aspect | |||
* Returns the singleton aspect or the percflow / percflowbelow associated with the current thread | |||
* | |||
* @param aspectClass | |||
* @return | |||
@@ -39,7 +42,9 @@ public class Aspects { | |||
*/ | |||
public static Object aspectOf(Class aspectClass) throws NoAspectBoundException { | |||
try { | |||
return getSingletonAspectOf(aspectClass).invoke(null, EMPTY_OBJECT_ARRAY); | |||
return getSingletonOrThreadAspectOf(aspectClass).invoke(null, EMPTY_OBJECT_ARRAY); | |||
} catch (InvocationTargetException e) { | |||
throw new NoAspectBoundException(aspectClass.getName(), e.getCause()); | |||
} catch (Exception e) { | |||
throw new NoAspectBoundException(aspectClass.getName(), e); | |||
} | |||
@@ -55,22 +60,78 @@ public class Aspects { | |||
public static Object aspectOf(Class aspectClass, Object perObject) throws NoAspectBoundException { | |||
try { | |||
return getPerObjectAspectOf(aspectClass).invoke(null, new Object[]{perObject}); | |||
} catch (InvocationTargetException e) { | |||
throw new NoAspectBoundException(aspectClass.getName(), e.getCause()); | |||
} catch (Exception e) { | |||
throw new NoAspectBoundException(aspectClass.getName(), e); | |||
} | |||
} | |||
public static Object aspectOf(Class aspectClass, Thread perThread) throws NoAspectBoundException { | |||
//TODO - how to know it s a real per Thread ? | |||
// if it is actually a singleton one, we will have it as well... | |||
/** | |||
* Returns the pertypewithin aspect | |||
* @param aspectClass | |||
* @param perTypeWithin class | |||
* @return | |||
* @throws NoAspectBoundException if no such aspect, or no aspect bound | |||
*/ | |||
public static Object aspectOf(Class aspectClass, Class perTypeWithin) throws NoAspectBoundException { | |||
try { | |||
return getSingletonAspectOf(aspectClass).invoke(null, EMPTY_OBJECT_ARRAY); | |||
return getPerTypeWithinAspectOf(aspectClass).invoke(null, new Object[]{perTypeWithin}); | |||
} catch (InvocationTargetException e) { | |||
throw new NoAspectBoundException(aspectClass.getName(), e.getCause()); | |||
} catch (Exception e) { | |||
throw new NoAspectBoundException(aspectClass.getName(), e); | |||
} | |||
} | |||
private static Method getSingletonAspectOf(Class aspectClass) throws NoSuchMethodException { | |||
/** | |||
* Returns true if singleton aspect or percflow / percflowbelow aspect is bound | |||
* | |||
* @param aspectClass | |||
* @return | |||
* @throws NoAspectBoundException if not bound | |||
*/ | |||
public static boolean hasAspect(Class aspectClass) throws NoAspectBoundException { | |||
try { | |||
return ((Boolean)getSingletonOrThreadHasAspect(aspectClass).invoke(null, EMPTY_OBJECT_ARRAY)).booleanValue(); | |||
} catch (Exception e) { | |||
return false; | |||
} | |||
} | |||
/** | |||
* Returns true if the perthis / pertarget aspect is bound | |||
* @param aspectClass | |||
* @param perObject | |||
* @return | |||
* @throws NoAspectBoundException if not bound | |||
*/ | |||
public static boolean hasAspect(Class aspectClass, Object perObject) throws NoAspectBoundException { | |||
try { | |||
return ((Boolean)getPerObjectHasAspect(aspectClass).invoke(null, new Object[]{perObject})).booleanValue(); | |||
} catch (Exception e) { | |||
return false; | |||
} | |||
} | |||
/** | |||
* Returns true if the pertypewithin aspect is bound | |||
* @param aspectClass | |||
* @param perTypeWithin class | |||
* @return | |||
* @throws NoAspectBoundException if not bound | |||
*/ | |||
public static boolean hasAspect(Class aspectClass, Class perTypeWithin) throws NoAspectBoundException { | |||
try { | |||
return ((Boolean)getPerTypeWithinHasAspect(aspectClass).invoke(null, new Object[]{perTypeWithin})).booleanValue(); | |||
} catch (Exception e) { | |||
return false; | |||
} | |||
} | |||
// -- aspectOf | |||
private static Method getSingletonOrThreadAspectOf(Class aspectClass) throws NoSuchMethodException { | |||
Method method = aspectClass.getDeclaredMethod(ASPECTOF, EMPTY_CLASS_ARRAY); | |||
return checkAspectOf(method, aspectClass); | |||
} | |||
@@ -80,8 +141,12 @@ public class Aspects { | |||
return checkAspectOf(method, aspectClass); | |||
} | |||
private static Method checkAspectOf(Method method, Class aspectClass) | |||
throws NoSuchMethodException { | |||
private static Method getPerTypeWithinAspectOf(Class aspectClass) throws NoSuchMethodException { | |||
Method method = aspectClass.getDeclaredMethod(ASPECTOF, PERTYPEWITHIN_CLASS_ARRAY); | |||
return checkAspectOf(method, aspectClass); | |||
} | |||
private static Method checkAspectOf(Method method, Class aspectClass) throws NoSuchMethodException { | |||
method.setAccessible(true); | |||
if (!method.isAccessible() | |||
|| !Modifier.isPublic(method.getModifiers()) | |||
@@ -90,4 +155,31 @@ public class Aspects { | |||
} | |||
return method; | |||
} | |||
// -- hasAspect | |||
private static Method getSingletonOrThreadHasAspect(Class aspectClass) throws NoSuchMethodException { | |||
Method method = aspectClass.getDeclaredMethod(HASASPECT, EMPTY_CLASS_ARRAY); | |||
return checkHasAspect(method, aspectClass); | |||
} | |||
private static Method getPerObjectHasAspect(Class aspectClass) throws NoSuchMethodException { | |||
Method method = aspectClass.getDeclaredMethod(HASASPECT, PEROBJECT_CLASS_ARRAY); | |||
return checkHasAspect(method, aspectClass); | |||
} | |||
private static Method getPerTypeWithinHasAspect(Class aspectClass) throws NoSuchMethodException { | |||
Method method = aspectClass.getDeclaredMethod(HASASPECT, PERTYPEWITHIN_CLASS_ARRAY); | |||
return checkHasAspect(method, aspectClass); | |||
} | |||
private static Method checkHasAspect(Method method, Class aspectClass) throws NoSuchMethodException { | |||
method.setAccessible(true); | |||
if (!method.isAccessible() | |||
|| !Modifier.isPublic(method.getModifiers()) | |||
|| !Modifier.isStatic(method.getModifiers())) { | |||
throw new NoSuchMethodException(aspectClass.getName() + ".hasAspect(..) is not accessible public static"); | |||
} | |||
return method; | |||
} | |||
} |
@@ -90,6 +90,10 @@ public class BindingTest extends TestCase { | |||
//assertEquals(2, aspect.m_count); | |||
} | |||
public void testTryCatch() { | |||
assertEquals(6, echo(3)); | |||
} | |||
private static void callWithinStatic() { | |||
int res = dup((3+1)); | |||
assertEquals(6, res); | |||
@@ -177,10 +181,18 @@ public class BindingTest extends TestCase { | |||
@Around("call(int echo(int)) && withincode(void ataspectj.BindingTest.testAccessAspectState()) && args(i)") | |||
public Object aaround7(int i, final ProceedingJoinPoint jp) throws Throwable { | |||
//m_count++;// what if inlined ? | |||
//m_count++;// what if inlined ?//FIXME | |||
return jp.proceed(); | |||
} | |||
@Around("call(int echo(int)) && withincode(void ataspectj.BindingTest.testTryCatch()) && args(i)") | |||
public Object aaround8(int i, final ProceedingJoinPoint jp) throws Throwable { | |||
try { | |||
return 2*((Integer)jp.proceed()).intValue(); | |||
} catch (Throwable t) { | |||
throw t; | |||
} | |||
} | |||
} | |||
} |
@@ -33,9 +33,46 @@ public class PerClauseTest extends TestCase { | |||
} | |||
public static junit.framework.Test suite() { | |||
return new junit.framework.TestSuite(AfterXTest.class); | |||
return new junit.framework.TestSuite(PerClauseTest.class); | |||
} | |||
public void perSingleton() { | |||
log("perSingleton"); | |||
} | |||
public void testPerSingleton() { | |||
s_log = new StringBuffer(); | |||
// singleton is bound as soon as clinit | |||
try { | |||
assertTrue(Aspects.hasAspect(TestAspectPerSingleton.class)); | |||
Aspects.aspectOf(TestAspectPerSingleton.class); | |||
} catch (NoAspectBoundException e) { | |||
fail(e.toString()); | |||
} | |||
perSingleton(); | |||
assertEquals("AOP.perSingleton perSingleton ", s_log.toString()); | |||
perSingleton(); | |||
assertEquals(1, TestAspectPerSingleton.s_count); | |||
} | |||
@Aspect() | |||
public static class TestAspectPerSingleton { | |||
static int s_count = 0; | |||
public TestAspectPerSingleton() { | |||
s_count++; | |||
} | |||
@Before("execution(* ataspectj.PerClauseTest.perSingleton()) && target(t)") | |||
public void before(JoinPoint jp, Object t) { | |||
log("AOP."+jp.getSignature().getName()); | |||
assertTrue("perX match", this.equals(Aspects.aspectOf(getClass()))); | |||
} | |||
} | |||
public void perTarget() { | |||
log("perTarget"); | |||
} | |||
@@ -45,8 +82,9 @@ public class PerClauseTest extends TestCase { | |||
perTarget(); | |||
assertEquals("AOP.perTarget perTarget ", s_log.toString()); | |||
// singleton | |||
// calling singleton API will fail | |||
try { | |||
assertFalse(Aspects.hasAspect(TestAspectPerTarget.class)); | |||
Aspects.aspectOf(TestAspectPerTarget.class); | |||
fail("should fail with NOABE"); | |||
} catch (NoAspectBoundException e) { | |||
@@ -55,6 +93,7 @@ public class PerClauseTest extends TestCase { | |||
// this per | |||
try { | |||
assertTrue(Aspects.hasAspect(TestAspectPerTarget.class, this)); | |||
TestAspectPerTarget aspect = (TestAspectPerTarget) Aspects.aspectOf(TestAspectPerTarget.class, this); | |||
assertNotNull(aspect); | |||
} catch (NoAspectBoundException e) { | |||
@@ -64,6 +103,7 @@ public class PerClauseTest extends TestCase { | |||
// another per | |||
PerClauseTest me = new PerClauseTest(); | |||
try { | |||
assertFalse(Aspects.hasAspect(TestAspectPerTarget.class, me)); | |||
Aspects.aspectOf(TestAspectPerTarget.class, me); | |||
fail("should fail"); | |||
} catch (NoAspectBoundException e) { | |||
@@ -71,18 +111,22 @@ public class PerClauseTest extends TestCase { | |||
} | |||
me.perTarget(); | |||
try { | |||
assertTrue(Aspects.hasAspect(TestAspectPerTarget.class, me)); | |||
TestAspectPerTarget aspect = (TestAspectPerTarget) Aspects.aspectOf(TestAspectPerTarget.class, me); | |||
assertNotNull(aspect); | |||
} catch (NoAspectBoundException e) { | |||
fail(e.toString()); | |||
} | |||
assertEquals(2, TestAspectPerTarget.s_count); | |||
} | |||
@Aspect("pertarget(execution(* ataspectj.PerClauseTest.perTarget()))") | |||
public static class TestAspectPerTarget { | |||
static int s_count; | |||
public TestAspectPerTarget() { | |||
; | |||
s_count++; | |||
} | |||
@Before("execution(* ataspectj.PerClauseTest.perTarget()) && target(t)") | |||
@@ -93,6 +137,13 @@ public class PerClauseTest extends TestCase { | |||
} | |||
public void perCflowEntry() { | |||
// the aspect is bound to the executing thread | |||
try { | |||
assertTrue(Aspects.hasAspect(TestAspectPerCflow.class)); | |||
Aspects.aspectOf(TestAspectPerCflow.class); | |||
} catch (NoAspectBoundException e) { | |||
fail(e.toString()); | |||
} | |||
perCflow(); | |||
} | |||
@@ -100,27 +151,126 @@ public class PerClauseTest extends TestCase { | |||
log("perCflow"); | |||
} | |||
public void testPerCflow() { | |||
public void testPerCflow() throws Throwable { | |||
s_log = new StringBuffer(); | |||
// no aspect bound yet | |||
try { | |||
assertFalse(Aspects.hasAspect(TestAspectPerCflow.class)); | |||
Aspects.aspectOf(TestAspectPerCflow.class); | |||
fail("No perCflow should be bound yet"); | |||
} catch (NoAspectBoundException e) { | |||
;//ok | |||
} | |||
perCflow(); | |||
assertEquals("perCflow ", s_log.toString()); | |||
// still no aspect bound yet | |||
try { | |||
assertFalse(Aspects.hasAspect(TestAspectPerCflow.class)); | |||
Aspects.aspectOf(TestAspectPerCflow.class); | |||
fail("No perCflow should be bound yet"); | |||
} catch (NoAspectBoundException e) { | |||
;//ok | |||
} | |||
s_log = new StringBuffer(); | |||
perCflowEntry(); | |||
assertEquals("AOP.perCflow perCflow ", s_log.toString()); | |||
// no aspect bound anymore since went OUT of the per clause | |||
try { | |||
assertFalse(Aspects.hasAspect(TestAspectPerCflow.class)); | |||
Aspects.aspectOf(TestAspectPerCflow.class); | |||
fail("No perCflow should be bound anymore"); | |||
} catch (NoAspectBoundException e) { | |||
;//ok | |||
} | |||
Runnable rok = new Runnable() { | |||
public void run() { | |||
perCflowEntry(); | |||
} | |||
}; | |||
Thread trok = new Thread(rok); | |||
trok.start(); | |||
trok.join(); | |||
Runnable rko = new Runnable() { | |||
public void run() { | |||
perCflow(); | |||
} | |||
}; | |||
Thread trko = new Thread(rko); | |||
trko.start(); | |||
trko.join(); | |||
assertEquals(2, TestAspectPerCflow.s_count); | |||
} | |||
@Aspect("percflow(execution(* ataspectj.PerClauseTest.perCflowEntry()))") | |||
public static class TestAspectPerCflow { | |||
static int s_count; | |||
public TestAspectPerCflow() { | |||
; | |||
s_count++; | |||
} | |||
@Before("execution(* ataspectj.PerClauseTest.perCflow())") | |||
public void before(JoinPoint jp) { | |||
log("AOP."+jp.getSignature().getName()); | |||
assertTrue("perX match", this.equals(Aspects.aspectOf(getClass(), Thread.currentThread()))); | |||
assertTrue("perX match", this.equals(Aspects.aspectOf(getClass()))); | |||
} | |||
} | |||
public void testPerTypeWithin() { | |||
assertTrue(Aspects.hasAspect(TestAspectPTW.class, PTW1.class)); | |||
assertTrue(Aspects.hasAspect(TestAspectPTW.class, PTW2.class)); | |||
assertFalse(Aspects.hasAspect(TestAspectPTW.class, PTWNoMatch.class)); | |||
PTW1.foo(); | |||
PTW2.foo(); | |||
PTWNoMatch.foo(); | |||
assertEquals(2, TestAspectPTW.s_count); | |||
try { | |||
assertTrue(Aspects.hasAspect(TestAspectPTW.class, PTW1.class)); | |||
assertTrue(Aspects.hasAspect(TestAspectPTW.class, PTW2.class)); | |||
Aspects.aspectOf(TestAspectPTW.class, PTW1.class); | |||
Aspects.aspectOf(TestAspectPTW.class, PTW2.class); | |||
} catch (NoAspectBoundException e) { | |||
fail(e.toString()); | |||
} | |||
try { | |||
assertFalse(Aspects.hasAspect(TestAspectPTW.class, PTWNoMatch.class)); | |||
Aspects.aspectOf(TestAspectPTW.class, PTWNoMatch.class); | |||
fail("should not have PTW aspect"); | |||
} catch (NoAspectBoundException e) { | |||
;//ok | |||
} | |||
} | |||
static class PTW1 { | |||
static void foo() {}; | |||
} | |||
static class PTW2 { | |||
static void foo() {}; | |||
} | |||
static class PTWNoMatch { | |||
static void foo() {}; | |||
} | |||
@Aspect("pertypewithin(ataspectj.PerClauseTest.PTW* && !ataspectj.PerClauseTest.PTWNoMatch)") | |||
public static class TestAspectPTW { | |||
static int s_count; | |||
public TestAspectPTW() { | |||
s_count++; | |||
} | |||
@Before("execution(* ataspectj.PerClauseTest.PTW*.foo())") | |||
public void before(JoinPoint jp) { | |||
; | |||
} | |||
} | |||
} |
@@ -1,208 +0,0 @@ | |||
<!-- @AspectJ v1.5.0 Tests --> | |||
<ajc-test dir="java5/ataspectj" title="SimpleBefore"> | |||
<compile files="SimpleBefore.java" options="-1.5 -showWeaveInfo -XnoInline"> | |||
<message kind="weave" text="(SimpleBefore.java:23) advised by before advice from 'SimpleBefore$X' (SimpleBefore.java:1)"/> | |||
</compile> | |||
<run class="SimpleBefore"/> | |||
<compile files="SimpleBefore.java" options="-1.5 -showWeaveInfo -XnoInline -Xdev:NoAtAspectJProcessing"> | |||
<message kind="weave" text="(SimpleBefore.java:23) advised by before advice from 'SimpleBefore$X' (SimpleBefore.java:1)"/> | |||
</compile> | |||
<run class="SimpleBefore"/> | |||
</ajc-test> | |||
<ajc-test dir="java5/ataspectj" title="SimpleAfter"> | |||
<compile files="SimpleAfter.java" options="-1.5 -showWeaveInfo -XnoInline"> | |||
<message kind="weave" text="(SimpleAfter.java:13) advised by after advice from 'SimpleAfter$X'"/> | |||
</compile> | |||
<run class="SimpleAfter"/> | |||
<compile files="SimpleAfter.java" options="-1.5 -showWeaveInfo -XnoInline -Xdev:NoAtAspectJProcessing"> | |||
<message kind="weave" text="(SimpleAfter.java:13) advised by after advice from 'SimpleAfter$X'"/> | |||
</compile> | |||
<run class="SimpleAfter"/> | |||
</ajc-test> | |||
<ajc-test dir="java5/ataspectj" title="singletonAspectBindings"> | |||
<compile files="ataspectj/SingletonAspectBindingsTest.java,ataspectj/TestHelper.java" options="-1.5 -XnoInline"/> | |||
<run class="ataspectj.SingletonAspectBindingsTest"/> | |||
<compile files="ataspectj/SingletonAspectBindingsTest.java,ataspectj/TestHelper.java" options="-1.5 -XnoInline -Xdev:NoAtAspectJProcessing"/> | |||
<run class="ataspectj.SingletonAspectBindingsTest"/> | |||
</ajc-test> | |||
<ajc-test dir="java5/ataspectj" title="CflowTest"> | |||
<compile files="ataspectj/CflowTest.java,ataspectj/TestHelper.java" options="-1.5"/> | |||
<run class="ataspectj.CflowTest"/> | |||
<compile files="ataspectj/CflowTest.java,ataspectj/TestHelper.java" options="-1.5 -Xdev:NoAtAspectJProcessing"/> | |||
<run class="ataspectj.CflowTest"/> | |||
</ajc-test> | |||
<ajc-test dir="java5/ataspectj" title="PointcutReferenceTest"> | |||
<compile files="ataspectj/PointcutReferenceTest.java,ataspectj/TestHelper.java" options="-1.5"/> | |||
<run class="ataspectj.PointcutReferenceTest"/> | |||
<compile files="ataspectj/PointcutReferenceTest.java,ataspectj/TestHelper.java" options="-1.5 -Xdev:NoAtAspectJProcessing"/> | |||
<run class="ataspectj.PointcutReferenceTest"/> | |||
</ajc-test> | |||
<ajc-test dir="java5/ataspectj" title="XXJoinPointTest"> | |||
<compile files="ataspectj/XXJoinPointTest.java,ataspectj/TestHelper.java" options="-1.5"/> | |||
<run class="ataspectj.XXJoinPointTest"/> | |||
<compile files="ataspectj/XXJoinPointTest.java,ataspectj/TestHelper.java" options="-1.5 -Xdev:NoAtAspectJProcessing"/> | |||
<run class="ataspectj.XXJoinPointTest"/> | |||
</ajc-test> | |||
<ajc-test dir="java5/ataspectj" title="PrecedenceTest"> | |||
<compile files="ataspectj/PrecedenceTest.java,ataspectj/TestHelper.java" options="-1.5"/> | |||
<run class="ataspectj.PrecedenceTest"/> | |||
<compile files="ataspectj/PrecedenceTest.java,ataspectj/TestHelper.java" options="-1.5 -Xdev:NoAtAspectJProcessing"/> | |||
<run class="ataspectj.PrecedenceTest"/> | |||
</ajc-test> | |||
<ajc-test dir="java5/ataspectj" title="AfterXTest"> | |||
<compile files="ataspectj/AfterXTest.java,ataspectj/TestHelper.java" options="-1.5"/> | |||
<run class="ataspectj.AfterXTest"/> | |||
</ajc-test> | |||
<ajc-test dir="java5/ataspectj" title="IfPointcutTest"> | |||
<compile files="ataspectj/IfPointcutTest.java,ataspectj/TestHelper.java" options="-1.5"/> | |||
<run class="ataspectj.IfPointcutTest"/> | |||
</ajc-test> | |||
<ajc-test dir="java5/ataspectj" title="BindingTest"> | |||
<compile files="ataspectj/BindingTest.java,ataspectj/TestHelper.java" options="-1.5"/> | |||
<run class="ataspectj.BindingTest"/> | |||
</ajc-test> | |||
<!-- ================================================================= --> | |||
<!-- Adrian's tests for generation of @AspectJ annotations from ajc --> | |||
<!-- ================================================================= --> | |||
<ajc-test dir="java5/ataspectj/annotationGen" title="annotation gen for simple aspect"> | |||
<compile files="SimpleAspect.aj" options="-1.5"/> | |||
<run class="SimpleAspect"/> | |||
</ajc-test> | |||
<ajc-test dir="java5/ataspectj/annotationGen" title="annotation gen for simple annotated aspect"> | |||
<compile files="SimpleAnnotatedAspect.aj" options="-1.5"/> | |||
<run class="SimpleAnnotatedAspect"/> | |||
</ajc-test> | |||
<ajc-test dir="java5/ataspectj/annotationGen" title="annotation gen for simple aspect pre 1.5"> | |||
<compile files="Simple14Aspect.aj" options="-1.4"/> | |||
<compile files="Simple14AspectTest.java" options="-1.5"/> | |||
<run class="Simple14AspectTest"/> | |||
</ajc-test> | |||
<ajc-test dir="java5/ataspectj/annotationGen" title="annotation gen for privileged aspect"> | |||
<compile files="PrivilegedAspect.aj" options="-1.5"/> | |||
<run class="PrivilegedAspect"/> | |||
</ajc-test> | |||
<ajc-test dir="java5/ataspectj/annotationGen" title="annotation gen for perthis aspect"> | |||
<compile files="PerThisAspect.aj" options="-1.5"/> | |||
<run class="PerThisAspect"/> | |||
</ajc-test> | |||
<ajc-test dir="java5/ataspectj/annotationGen" title="annotation gen for pertarget aspect"> | |||
<compile files="PerTargetAspect.aj" options="-1.5"/> | |||
<run class="PerTargetAspect"/> | |||
</ajc-test> | |||
<ajc-test dir="java5/ataspectj/annotationGen" title="annotation gen for percflow aspect"> | |||
<compile files="PerCflowAspect.aj" options="-1.5"/> | |||
<run class="PerCflowAspect"/> | |||
</ajc-test> | |||
<ajc-test dir="java5/ataspectj/annotationGen" title="annotation gen for percflowbelow aspect"> | |||
<compile files="PerCflowbelowAspect.aj" options="-1.5"/> | |||
<run class="PerCflowbelowAspect"/> | |||
</ajc-test> | |||
<ajc-test dir="java5/ataspectj/annotationGen" title="annotation gen for pertypewithin aspect"> | |||
<compile files="PerTypeWithinAspect.aj" options="-1.5"/> | |||
<run class="PerTypeWithinAspect"/> | |||
</ajc-test> | |||
<ajc-test dir="java5/ataspectj/annotationGen" title="annotation gen for inner aspect of aspect"> | |||
<compile files="InnerAspectAspect.aj" options="-1.5"/> | |||
<run class="InnerAspectAspect"/> | |||
</ajc-test> | |||
<ajc-test dir="java5/ataspectj/annotationGen" title="annotation gen for inner aspect of class"> | |||
<compile files="InnerAspectClass.aj" options="-1.5"/> | |||
<run class="InnerAspectClass"/> | |||
</ajc-test> | |||
<ajc-test dir="java5/ataspectj/annotationGen" title="annotation gen for advice declarations"> | |||
<compile files="BasicAdvice.aj" options="-1.5"/> | |||
<run class="BasicAdvice"/> | |||
</ajc-test> | |||
<ajc-test dir="java5/ataspectj/annotationGen" title="annotation gen for simple pointcut"> | |||
<compile files="SimplePointcut.aj" options="-1.5"/> | |||
<run class="SimplePointcut"/> | |||
</ajc-test> | |||
<ajc-test dir="java5/ataspectj/annotationGen" title="annotation gen for pointcut modifiers"> | |||
<compile files="PointcutModifiers.aj" options="-1.5"/> | |||
<run class="PointcutModifiers"/> | |||
</ajc-test> | |||
<ajc-test dir="java5/ataspectj/annotationGen" title="annotation gen for pointcut params"> | |||
<compile files="PointcutsWithParams.aj" options="-1.5"/> | |||
<run class="PointcutsWithParams"/> | |||
</ajc-test> | |||
<ajc-test dir="java5/ataspectj/annotationGen" title="annotation gen for pointcut refs"> | |||
<compile files="ReferencePointcuts.aj" options="-1.5"/> | |||
<run class="ReferencePointcuts"/> | |||
</ajc-test> | |||
<ajc-test dir="java5/ataspectj/annotationGen" title="before ann with non-void return"> | |||
<compile files="BeforeWithBadReturn.java" options="-1.5"> | |||
<message kind="error" line="7" text="This advice must return void"/> | |||
<message kind="error" line="7" text="This method must return a result of type String"/> | |||
</compile> | |||
</ajc-test> | |||
<ajc-test dir="java5/ataspectj/annotationGen" title="two anns on same element"> | |||
<compile files="TwoForThePriceOfOne.java" options="-1.5"> | |||
<message kind="error" line="7" text="The annotation @Pointcut is disallowed for this location"/> | |||
</compile> | |||
</ajc-test> | |||
<ajc-test dir="java5/ataspectj/annotationGen" title="bad pcut in after advice"> | |||
<compile files="AfterReturningWithBadPCut.java" options="-1.5"> | |||
<message kind="error" line="6" text="Syntax error on token "excution(* *.*(..))""/> | |||
</compile> | |||
</ajc-test> | |||
<ajc-test dir="java5/ataspectj/annotationGen" title="bad parameter binding in advice"> | |||
<compile files="BadParameterBinding.java" options="-1.5"> | |||
<message kind="warning" line="11" text="no match for this type name: bpb"/> | |||
<message kind="warning" line="15" text="no match for this type name: TheUnknownType"/> | |||
</compile> | |||
</ajc-test> | |||
<ajc-test dir="java5/ataspectj/annotationGen" title="simple pointcut no params"> | |||
<compile files="APointcut.java" options="-1.5"/> | |||
<run class="APointcut"/> | |||
</ajc-test> | |||
<ajc-test dir="java5/ataspectj/annotationGen" title="pointcut medley"> | |||
<compile files="PointcutAssortment.java" options="-1.5"> | |||
<message kind="error" line="9" text="Methods annotated with @Pointcut must return void"/> | |||
<message kind="error" line="9" text="This method must return a result of type String"/> | |||
<message kind="error" line="15" text="Pointcuts should have an empty method body"/> | |||
<message kind="error" line="28" text="Duplicate annotation @Pointcut"/> | |||
<message kind="error" line="29" text="Duplicate annotation @Pointcut"/> | |||
<message kind="error" line="11" text="can't find referenced pointcut foo"/> | |||
<message kind="warning" line="32" text="no match for this type name: foo [Xlint:invalidAbsoluteTypeName]"/> | |||
</compile> | |||
</ajc-test> | |||
<ajc-test dir="java5/ataspectj/annotationGen" title="advice in a class"> | |||
<compile files="AdviceInAClass.java" options="-1.5"> | |||
<message kind="error" line="6" text="Advice must be declared inside an aspect type"/> | |||
</compile> | |||
</ajc-test> | |||
@@ -1,12 +0,0 @@ | |||
<!DOCTYPE suite SYSTEM "../tests/ajcTestSuite.dtd"[ | |||
<!ENTITY tests SYSTEM "../tests/src/org/aspectj/systemtest/ajc150/ataspectj/atajc150-tests.xml"> | |||
]> | |||
<!-- @AspectJ v1.5.0 Tests --> | |||
<suite> | |||
&tests; | |||
</suite> | |||
@@ -79,4 +79,12 @@ | |||
<compile files="ataspectj/BindingTest.java,ataspectj/TestHelper.java" options="-1.5 -XnoInline"/> | |||
<run class="ataspectj.BindingTest"/> | |||
</ajc-test> | |||
<ajc-test dir="java5/ataspectj" title="PerClause"> | |||
<compile files="ataspectj/PerClauseTest.java,ataspectj/TestHelper.java" options="-1.5 -Xdev:NoAtAspectJProcessing"/> | |||
<run class="ataspectj.PerClauseTest"/> | |||
<compile files="ataspectj/PerClauseTest.java,ataspectj/TestHelper.java" options="-1.5"/> | |||
<run class="ataspectj.PerClauseTest"/> | |||
</ajc-test> | |||
</suite> |
@@ -223,8 +223,14 @@ public class AjdeInteractionTestbed extends TestCase { | |||
// AMC - I did this rather than use the JDK default as I hate having to go look | |||
// in c:\documents and settings\......... for the results of a failed test. | |||
if (os.startsWith("Windows")) { | |||
tempDir = new File("C:\\temp"); | |||
if (!tempDir.exists()) {tempDir.mkdir();} | |||
//Alex: try D first since NTFS on mine while FAT leads to failure.. | |||
tempDir = new File("D:\\temp"); | |||
if (!tempDir.exists()) { | |||
tempDir = new File("C:\\temp"); | |||
if (!tempDir.exists()) { | |||
tempDir.mkdir(); | |||
} | |||
} | |||
} else { | |||
tempDir = new File("/tmp"); | |||
} |
@@ -160,7 +160,15 @@ public class AjcMemberMaker { | |||
TypeX.forSignature("Ljava/lang/String;"), NameMangler.PERTYPEWITHIN_WITHINTYPEFIELD, TypeX.NONE); | |||
} | |||
public static ResolvedMember perTypeWithinPerClassMapField(ResolvedTypeX aspectType) { | |||
int modifiers = Modifier.PRIVATE; | |||
if (!TypeX.SERIALIZABLE.isAssignableFrom(aspectType, aspectType.getWorld())) { | |||
modifiers |= Modifier.TRANSIENT; | |||
} | |||
return new ResolvedMember(Member.FIELD, aspectType, modifiers, | |||
TypeX.forSignature("Ljava/util/Map;"), "instances", TypeX.NONE); | |||
} | |||
public static ResolvedMember perObjectBind(TypeX declaringType) { | |||
return new ResolvedMember( | |||
Member.METHOD, | |||
@@ -184,7 +192,22 @@ public class AjcMemberMaker { | |||
); | |||
return rm; | |||
} | |||
// PTWIMPL ResolvedMember for "Set getInstances()" method, declared in aspect | |||
public static ResolvedMember perTypeWithinGetInstancesSet(TypeX declaringType) { | |||
// public Set getInstances() | |||
ResolvedMember rm = new ResolvedMember( | |||
Member.METHOD, | |||
declaringType, | |||
Modifier.PUBLIC, | |||
TypeX.forSignature("Ljava/util/Set;"), | |||
"getInstances", | |||
TypeX.NONE, | |||
TypeX.NONE | |||
); | |||
return rm; | |||
} | |||
public static ResolvedMember perTypeWithinCreateAspectInstance(TypeX declaringType) { | |||
// public static a.X ajc$createAspectInstance(java.lang.String) | |||
ResolvedMember rm = new ResolvedMember( |
@@ -27,6 +27,13 @@ import org.aspectj.apache.bcel.generic.POP; | |||
import org.aspectj.apache.bcel.generic.PUSH; | |||
import org.aspectj.apache.bcel.generic.ReferenceType; | |||
import org.aspectj.apache.bcel.generic.Type; | |||
import org.aspectj.apache.bcel.generic.MethodGen; | |||
import org.aspectj.apache.bcel.generic.RETURN; | |||
import org.aspectj.apache.bcel.generic.NEW; | |||
import org.aspectj.apache.bcel.generic.INVOKESPECIAL; | |||
import org.aspectj.apache.bcel.generic.ASTORE; | |||
import org.aspectj.apache.bcel.generic.ACONST_NULL; | |||
import org.aspectj.apache.bcel.generic.IRETURN; | |||
import org.aspectj.weaver.AjcMemberMaker; | |||
import org.aspectj.weaver.Member; | |||
import org.aspectj.weaver.NameMangler; | |||
@@ -35,6 +42,8 @@ import org.aspectj.weaver.ResolvedTypeX; | |||
import org.aspectj.weaver.TypeX; | |||
import org.aspectj.weaver.patterns.PerClause; | |||
import java.util.Iterator; | |||
/** | |||
* Adds aspectOf, hasAspect etc to the annotation defined aspects | |||
* | |||
@@ -58,8 +67,12 @@ public class BcelPerClauseAspectAdder extends BcelTypeMunger { | |||
public boolean munge(BcelClassWeaver weaver) { | |||
LazyClassGen gen = weaver.getLazyClassGen(); | |||
// agressively generate the inner interface | |||
// agressively generate the inner interface if any | |||
// Note: we do so because of the bug that leads to have this interface implemented by all classes and not | |||
// only those matched by the per clause, which fails under LTW since the very first class | |||
// gets weaved and impl this interface that is still not defined. | |||
if (!hasGeneratedInner) { | |||
//FIXME AV - restore test below or ?? + add test to detect such side effect | |||
//if (kind == PerClause.PEROBJECT || kind == PerClause.PERCFLOW) { | |||
//inner class | |||
TypeX interfaceTypeX = AjcMemberMaker.perObjectInterfaceType(aspectType); | |||
@@ -99,6 +112,12 @@ public class BcelPerClauseAspectAdder extends BcelTypeMunger { | |||
generatePerCflowHasAspectMethod(gen); | |||
generatePerCflowPushMethod(gen); | |||
generatePerCflowAjcClinitMethod(gen); | |||
} else if (kind == PerClause.PERTYPEWITHIN) { | |||
generatePerTWGetInstancesMethod(gen); | |||
generatePerTWAspectOfMethod(gen); | |||
generatePerTWHasAspectMethod(gen); | |||
generatePerTWGetInstanceMethod(gen); | |||
generatePerTWCreateAspectInstanceMethod(gen); | |||
} else { | |||
throw new RuntimeException("TODO not yet implemented perClause " + kind.getName()); | |||
} | |||
@@ -135,31 +154,45 @@ public class BcelPerClauseAspectAdder extends BcelTypeMunger { | |||
} else if (kind == PerClause.PEROBJECT) { | |||
ResolvedMember perObjectFieldInfo = AjcMemberMaker.perObjectField(aspectType, aspectType); | |||
classGen.addField(makeFieldGen(classGen, perObjectFieldInfo).getField(), null); | |||
// //inner class | |||
// TypeX interfaceTypeX = AjcMemberMaker.perObjectInterfaceType(aspectType); | |||
// LazyClassGen interfaceGen = new LazyClassGen( | |||
// interfaceTypeX.getName(), | |||
// "java.lang.Object", | |||
// null, | |||
// Constants.ACC_PRIVATE + Constants.ACC_ABSTRACT, | |||
// new String[0] | |||
// ); | |||
// interfaceGen.addMethodGen(makeMethodGen(interfaceGen, AjcMemberMaker.perObjectInterfaceGet(aspectType))); | |||
// interfaceGen.addMethodGen(makeMethodGen(interfaceGen, AjcMemberMaker.perObjectInterfaceSet(aspectType))); | |||
// classGen.addGeneratedInner(interfaceGen); | |||
// if lazy generation of the inner interface MayHaveAspect works on LTW (see previous note) | |||
// it should be done here. | |||
} else if (kind == PerClause.PERCFLOW) { | |||
ResolvedMember perCflowFieldInfo = AjcMemberMaker.perCflowField(aspectType); | |||
classGen.addField(makeFieldGen(classGen, perCflowFieldInfo).getField(), null); | |||
} else if (kind == PerClause.PERTYPEWITHIN) { | |||
ResolvedMember perTypeWithinForField = AjcMemberMaker.perTypeWithinWithinTypeField(aspectType, aspectType); | |||
classGen.addField(makeFieldGen(classGen, perTypeWithinForField).getField(), null); | |||
ResolvedMember perTypeWithinPerClassMapField = AjcMemberMaker.perTypeWithinPerClassMapField(aspectType); | |||
classGen.addField(makeFieldGen(classGen, perTypeWithinPerClassMapField).getField(), null); | |||
// we need to initialize this map as a WeakHashMap in the aspect constructor(s) | |||
InstructionFactory factory = classGen.getFactory(); | |||
for (Iterator iterator = classGen.getMethodGens().iterator(); iterator.hasNext();) { | |||
LazyMethodGen methodGen = (LazyMethodGen) iterator.next(); | |||
if ("<init>".equals(methodGen.getName())) { | |||
InstructionList il = new InstructionList(); | |||
il.append(InstructionConstants.ALOAD_0); | |||
il.append(Utility.createGet(factory, perTypeWithinPerClassMapField)); | |||
BranchInstruction ifNotNull = InstructionFactory.createBranchInstruction(Constants.IFNONNULL, null); | |||
il.append(ifNotNull); | |||
il.append(InstructionConstants.ALOAD_0); | |||
il.append(factory.createNew("java/util/WeakHashMap")); | |||
il.append(new DUP()); | |||
il.append(factory.createInvoke( | |||
"java/util/WeakHashMap", | |||
"<init>", | |||
Type.VOID, | |||
Type.NO_ARGS, | |||
Constants.INVOKESPECIAL | |||
)); | |||
il.append(Utility.createSet(factory, perTypeWithinPerClassMapField)); | |||
InstructionHandle currentEnd = methodGen.getBody().getEnd(); | |||
ifNotNull.setTarget(currentEnd); | |||
methodGen.getBody().insert(currentEnd, il); | |||
} | |||
} | |||
} else { | |||
throw new RuntimeException("TODO not implemented yet"); | |||
throw new Error("Should not happen - no such kind " + kind.toString()); | |||
} | |||
// } else if (kind == PerClause.PERTYPEWITHIN) { | |||
// //PTWIMPL Add field for storing typename in aspect for which the aspect instance exists | |||
// binding.addField(factory.makeFieldBinding(AjcMemberMaker.perTypeWithinWithinTypeField(typeX,typeX))); | |||
// } else { | |||
// throw new RuntimeException("unimplemented"); | |||
// } | |||
} | |||
private void generatePerSingletonAspectOfMethod(LazyClassGen classGen) { | |||
@@ -217,8 +250,8 @@ public class BcelPerClauseAspectAdder extends BcelTypeMunger { | |||
InstructionHandle tryStart = il.append(factory.createInvoke(aspectType.getName(), NameMangler.AJC_POST_CLINIT_NAME, Type.VOID, Type.NO_ARGS, Constants.INVOKESTATIC)); | |||
BranchInstruction tryEnd = InstructionFactory.createBranchInstruction(Constants.GOTO, null); | |||
il.append(tryEnd); | |||
InstructionHandle handler = il.append(InstructionFactory.createStore(Type.OBJECT, 0)); | |||
il.append(InstructionFactory.createLoad(Type.OBJECT, 0)); | |||
InstructionHandle handler = il.append(InstructionConstants.ASTORE_0); | |||
il.append(InstructionConstants.ALOAD_0); | |||
il.append(Utility.createSet(factory, AjcMemberMaker.initFailureCauseField(aspectType))); | |||
il.append(InstructionFactory.createReturn(Type.VOID)); | |||
tryEnd.setTarget(il.getEnd()); | |||
@@ -239,14 +272,14 @@ public class BcelPerClauseAspectAdder extends BcelTypeMunger { | |||
classGen.addMethodGen(method); | |||
InstructionList il = method.getBody(); | |||
il.append(new ALOAD(0)); | |||
il.append(InstructionConstants.ALOAD_0); | |||
il.append(factory.createInstanceOf(interfaceType)); | |||
BranchInstruction ifEq = InstructionFactory.createBranchInstruction(Constants.IFEQ, null); | |||
il.append(ifEq); | |||
il.append(new ALOAD(0)); | |||
il.append(InstructionConstants.ALOAD_0); | |||
il.append(factory.createCheckCast(interfaceType)); | |||
il.append(Utility.createInvoke(factory, Constants.INVOKEINTERFACE, AjcMemberMaker.perObjectInterfaceGet(aspectType))); | |||
il.append(new DUP()); | |||
il.append(InstructionConstants.DUP); | |||
BranchInstruction ifNull = InstructionFactory.createBranchInstruction(Constants.IFNULL, null); | |||
il.append(ifNull); | |||
il.append(InstructionFactory.createReturn(BcelWorld.makeBcelType(aspectType))); | |||
@@ -254,7 +287,7 @@ public class BcelPerClauseAspectAdder extends BcelTypeMunger { | |||
ifNull.setTarget(ifNullElse); | |||
InstructionHandle ifEqElse = il.append(factory.createNew(AjcMemberMaker.NO_ASPECT_BOUND_EXCEPTION.getName())); | |||
ifEq.setTarget(ifEqElse); | |||
il.append(new DUP()); | |||
il.append(InstructionConstants.DUP); | |||
il.append(factory.createInvoke(AjcMemberMaker.NO_ASPECT_BOUND_EXCEPTION.getName(), "<init>", Type.VOID, Type.NO_ARGS, Constants.INVOKESPECIAL)); | |||
il.append(new ATHROW()); | |||
} | |||
@@ -266,20 +299,20 @@ public class BcelPerClauseAspectAdder extends BcelTypeMunger { | |||
classGen.addMethodGen(method); | |||
InstructionList il = method.getBody(); | |||
il.append(new ALOAD(0)); | |||
il.append(InstructionConstants.ALOAD_0); | |||
il.append(factory.createInstanceOf(interfaceType)); | |||
BranchInstruction ifEq = InstructionFactory.createBranchInstruction(Constants.IFEQ, null); | |||
il.append(ifEq); | |||
il.append(new ALOAD(0)); | |||
il.append(InstructionConstants.ALOAD_0); | |||
il.append(factory.createCheckCast(interfaceType)); | |||
il.append(Utility.createInvoke(factory, Constants.INVOKEINTERFACE, AjcMemberMaker.perObjectInterfaceGet(aspectType))); | |||
BranchInstruction ifNull = InstructionFactory.createBranchInstruction(Constants.IFNULL, null); | |||
il.append(ifNull); | |||
il.append(new ICONST(1));//TODO is ok ? else Push boolean | |||
il.append(InstructionConstants.ICONST_1); | |||
il.append(InstructionFactory.createReturn(Type.INT)); | |||
InstructionHandle ifEqElse = il.append(new ICONST(0)); | |||
InstructionHandle ifEqElse = il.append(InstructionConstants.ICONST_0); | |||
ifEq.setTarget(ifEqElse); | |||
ifNull.setTarget(ifEqElse);//?? | |||
ifNull.setTarget(ifEqElse);//??//FIXME AV - ok or what ? | |||
il.append(InstructionFactory.createReturn(Type.INT)); | |||
} | |||
@@ -290,16 +323,16 @@ public class BcelPerClauseAspectAdder extends BcelTypeMunger { | |||
classGen.addMethodGen(method); | |||
InstructionList il = method.getBody(); | |||
il.append(new ALOAD(0)); | |||
il.append(InstructionConstants.ALOAD_0); | |||
il.append(factory.createInstanceOf(interfaceType)); | |||
BranchInstruction ifEq = InstructionFactory.createBranchInstruction(Constants.IFEQ, null); | |||
il.append(ifEq); | |||
il.append(new ALOAD(0)); | |||
il.append(InstructionConstants.ALOAD_0); | |||
il.append(factory.createCheckCast(interfaceType)); | |||
il.append(Utility.createInvoke(factory, Constants.INVOKEINTERFACE, AjcMemberMaker.perObjectInterfaceGet(aspectType))); | |||
BranchInstruction ifNonNull = InstructionFactory.createBranchInstruction(Constants.IFNONNULL, null); | |||
il.append(ifNonNull); | |||
il.append(new ALOAD(0)); | |||
il.append(InstructionConstants.ALOAD_0); | |||
il.append(factory.createCheckCast(interfaceType)); | |||
il.append(factory.createNew(aspectType.getName())); | |||
il.append(InstructionConstants.DUP); | |||
@@ -317,7 +350,7 @@ public class BcelPerClauseAspectAdder extends BcelTypeMunger { | |||
classGen.addMethodGen(methodGet); | |||
InstructionList ilGet = methodGet.getBody(); | |||
ilGet = new InstructionList(); | |||
ilGet.append(new ALOAD(0)); | |||
ilGet.append(InstructionConstants.ALOAD_0); | |||
ilGet.append(Utility.createGet(factory, AjcMemberMaker.perObjectField(aspectType, aspectType))); | |||
ilGet.append(InstructionFactory.createReturn(Type.OBJECT)); | |||
@@ -325,8 +358,8 @@ public class BcelPerClauseAspectAdder extends BcelTypeMunger { | |||
classGen.addMethodGen(methodSet); | |||
InstructionList ilSet = methodSet.getBody(); | |||
ilSet = new InstructionList(); | |||
ilSet.append(new ALOAD(0)); | |||
ilSet.append(new ALOAD(1)); | |||
ilSet.append(InstructionConstants.ALOAD_0); | |||
ilSet.append(InstructionConstants.ALOAD_1); | |||
ilSet.append(Utility.createSet(factory, AjcMemberMaker.perObjectField(aspectType, aspectType))); | |||
ilSet.append(InstructionFactory.createReturn(Type.VOID)); | |||
} | |||
@@ -387,4 +420,144 @@ public class BcelPerClauseAspectAdder extends BcelTypeMunger { | |||
clinit.getBody().insert(il); | |||
} | |||
private void generatePerTWGetInstancesMethod(LazyClassGen classGen) { | |||
InstructionFactory factory = classGen.getFactory(); | |||
LazyMethodGen method = makeMethodGen(classGen, AjcMemberMaker.perTypeWithinGetInstancesSet(aspectType)); | |||
classGen.addMethodGen(method); | |||
InstructionList il = method.getBody(); | |||
il.append(InstructionConstants.ALOAD_0); | |||
il.append(Utility.createGet(factory, AjcMemberMaker.perTypeWithinPerClassMapField(aspectType))); | |||
il.append(factory.createInvoke( | |||
"java/util/Map", "keySet", Type.getType("Ljava/util/Set;"), Type.NO_ARGS, Constants.INVOKEINTERFACE | |||
)); | |||
il.append(InstructionFactory.createReturn(Type.OBJECT)); | |||
} | |||
private void generatePerTWAspectOfMethod(LazyClassGen classGen) { | |||
InstructionFactory factory = classGen.getFactory(); | |||
LazyMethodGen method = makeMethodGen(classGen, AjcMemberMaker.perTypeWithinAspectOfMethod(aspectType)); | |||
classGen.addMethodGen(method); | |||
InstructionList il = method.getBody(); | |||
InstructionHandle tryStart = il.append(InstructionConstants.ALOAD_0); | |||
il.append(Utility.createInvoke( | |||
factory, | |||
Constants.INVOKESTATIC, | |||
AjcMemberMaker.perTypeWithinGetInstance(aspectType) | |||
)); | |||
il.append(InstructionConstants.ASTORE_1); | |||
il.append(InstructionConstants.ALOAD_1); | |||
BranchInstruction ifNonNull = InstructionFactory.createBranchInstruction(Constants.IFNONNULL, null); | |||
il.append(ifNonNull); | |||
il.append(factory.createNew(AjcMemberMaker.NO_ASPECT_BOUND_EXCEPTION.getName())); | |||
il.append(InstructionConstants.DUP); | |||
il.append(new PUSH(classGen.getConstantPoolGen(), aspectType.getName())); | |||
il.append(InstructionConstants.ACONST_NULL); | |||
il.append(factory.createInvoke(AjcMemberMaker.NO_ASPECT_BOUND_EXCEPTION.getName(), "<init>", Type.VOID, new Type[] { Type.STRING, new ObjectType("java.lang.Throwable") }, Constants.INVOKESPECIAL)); | |||
il.append(InstructionConstants.ATHROW); | |||
InstructionHandle ifElse = il.append(InstructionConstants.ALOAD_1); | |||
ifNonNull.setTarget(ifElse); | |||
il.append(InstructionFactory.createReturn(Type.OBJECT)); | |||
InstructionHandle handler = il.append(InstructionConstants.ASTORE_1); | |||
il.append(factory.createNew(AjcMemberMaker.NO_ASPECT_BOUND_EXCEPTION.getName())); | |||
il.append(InstructionConstants.DUP); | |||
il.append(factory.createInvoke(AjcMemberMaker.NO_ASPECT_BOUND_EXCEPTION.getName(), "<init>", Type.VOID, Type.NO_ARGS, Constants.INVOKESPECIAL)); | |||
il.append(InstructionConstants.ATHROW); | |||
method.addExceptionHandler( | |||
tryStart, handler.getPrev(), handler, new ObjectType("java.lang.Exception"), false | |||
); | |||
} | |||
private void generatePerTWHasAspectMethod(LazyClassGen classGen) { | |||
InstructionFactory factory = classGen.getFactory(); | |||
LazyMethodGen method = makeMethodGen(classGen, AjcMemberMaker.perTypeWithinHasAspectMethod(aspectType)); | |||
classGen.addMethodGen(method); | |||
InstructionList il = method.getBody(); | |||
InstructionHandle tryStart = il.append(InstructionConstants.ALOAD_0); | |||
il.append(Utility.createInvoke( | |||
factory, | |||
Constants.INVOKESTATIC, | |||
AjcMemberMaker.perTypeWithinGetInstance(aspectType) | |||
)); | |||
BranchInstruction ifNull = InstructionFactory.createBranchInstruction(Constants.IFNULL, null); | |||
il.append(ifNull); | |||
il.append(InstructionConstants.ICONST_1); | |||
il.append(InstructionConstants.IRETURN); | |||
InstructionHandle ifElse = il.append(InstructionConstants.ICONST_0); | |||
ifNull.setTarget(ifElse); | |||
il.append(InstructionConstants.IRETURN); | |||
InstructionHandle handler = il.append(InstructionConstants.ASTORE_1); | |||
il.append(InstructionConstants.ICONST_0); | |||
il.append(InstructionConstants.IRETURN); | |||
method.addExceptionHandler( | |||
tryStart, handler.getPrev(), handler, new ObjectType("java.lang.Exception"), false | |||
); | |||
} | |||
private void generatePerTWGetInstanceMethod(LazyClassGen classGen) { | |||
InstructionFactory factory = classGen.getFactory(); | |||
LazyMethodGen method = makeMethodGen(classGen, AjcMemberMaker.perTypeWithinGetInstance(aspectType)); | |||
classGen.addMethodGen(method); | |||
InstructionList il = method.getBody(); | |||
InstructionHandle tryStart = il.append(InstructionConstants.ALOAD_0); | |||
il.append(new PUSH(factory.getConstantPool(), NameMangler.perTypeWithinLocalAspectOf(aspectType))); | |||
il.append(InstructionConstants.ACONST_NULL);//Class[] for "getDeclaredMethod" | |||
il.append(factory.createInvoke( | |||
"java/lang/Class", | |||
"getDeclaredMethod", | |||
Type.getType("Ljava/lang/reflect/Method;"), | |||
new Type[]{Type.getType("Ljava/lang/String;"), Type.getType("[Ljava/lang/Class;")}, | |||
Constants.INVOKEVIRTUAL | |||
)); | |||
il.append(InstructionConstants.ACONST_NULL);//Object for "invoke", static method | |||
il.append(InstructionConstants.ACONST_NULL);//Object[] for "invoke", no arg | |||
il.append(factory.createInvoke( | |||
"java/lang/reflect/Method", | |||
"invoke", | |||
Type.OBJECT, | |||
new Type[]{Type.getType("Ljava/lang/Object;"), Type.getType("[Ljava/lang/Object;")}, | |||
Constants.INVOKEVIRTUAL | |||
)); | |||
il.append(factory.createCheckCast((ReferenceType) BcelWorld.makeBcelType(aspectType))); | |||
il.append(InstructionConstants.ARETURN); | |||
InstructionHandle handler = il.append(InstructionConstants.ASTORE_1); | |||
il.append(InstructionConstants.ALOAD_1); | |||
il.append(InstructionConstants.ATHROW); | |||
method.addExceptionHandler( | |||
tryStart, handler.getPrev(), handler, new ObjectType("java.lang.Exception"), false | |||
); | |||
} | |||
private void generatePerTWCreateAspectInstanceMethod(LazyClassGen classGen) { | |||
InstructionFactory factory = classGen.getFactory(); | |||
LazyMethodGen method = makeMethodGen(classGen, AjcMemberMaker.perTypeWithinCreateAspectInstance(aspectType)); | |||
classGen.addMethodGen(method); | |||
InstructionList il = method.getBody(); | |||
il.append(factory.createNew(aspectType.getName())); | |||
il.append(InstructionConstants.DUP); | |||
il.append(factory.createInvoke( | |||
aspectType.getName(), "<init>", Type.VOID, Type.NO_ARGS, Constants.INVOKESPECIAL | |||
)); | |||
il.append(InstructionConstants.ASTORE_1); | |||
il.append(InstructionConstants.ALOAD_1); | |||
il.append(InstructionConstants.ALOAD_0); | |||
il.append(Utility.createSet( | |||
factory, | |||
AjcMemberMaker.perTypeWithinWithinTypeField(aspectType, aspectType) | |||
)); | |||
il.append(InstructionConstants.ALOAD_1); | |||
il.append(InstructionConstants.ARETURN); | |||
} | |||
} |
@@ -145,6 +145,14 @@ public class PerTypeWithin extends PerClause { | |||
ResolvedTypeMunger munger = new PerTypeWithinTargetTypeMunger(inAspect, ret); | |||
inAspect.crosscuttingMembers.addTypeMunger(world.concreteTypeMunger(munger, inAspect)); | |||
//ATAJ: add a munger to add the aspectOf(..) to the @AJ aspects | |||
if (inAspect.isAnnotationStyleAspect()) { | |||
inAspect.crosscuttingMembers.addTypeMunger( | |||
inAspect.getWorld().makePerClauseAspect(inAspect, getKind()) | |||
); | |||
} | |||
return ret; | |||
} |