From: acolyer Date: Mon, 19 Dec 2005 14:22:04 +0000 (+0000) Subject: merge of @DeclareParents fix from HEAD into 1.5.0 release branch X-Git-Tag: V1_5_0_final~7 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=58522e68b73dcf87dfabad2326988373ae8f004e;p=aspectj.git merge of @DeclareParents fix from HEAD into 1.5.0 release branch --- diff --git a/aspectj5rt/java5-src/org/aspectj/lang/annotation/DeclareImplements.java b/aspectj5rt/java5-src/org/aspectj/lang/annotation/DeclareImplements.java deleted file mode 100644 index dbb1bf1d9..000000000 --- a/aspectj5rt/java5-src/org/aspectj/lang/annotation/DeclareImplements.java +++ /dev/null @@ -1,31 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2005 Contributors. - * All rights reserved. - * This program and the accompanying materials are made available - * under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution and is available at - * http://eclipse.org/legal/epl-v10.html - * - * Contributors: - * initial implementation Adrian Colyer - *******************************************************************************/ -package org.aspectj.lang.annotation; - -import java.lang.annotation.Target; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Declare parents mixin annotation - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface DeclareImplements { - - /** - * The target types expression - */ - String value(); - -} diff --git a/aspectj5rt/java5-src/org/aspectj/lang/annotation/DeclareParents.java b/aspectj5rt/java5-src/org/aspectj/lang/annotation/DeclareParents.java index fe7267849..b7c2452e2 100644 --- a/aspectj5rt/java5-src/org/aspectj/lang/annotation/DeclareParents.java +++ b/aspectj5rt/java5-src/org/aspectj/lang/annotation/DeclareParents.java @@ -27,7 +27,7 @@ public @interface DeclareParents { * The target types expression */ String value(); - + /** * Optional class defining default implementation * of interface members (equivalent to defining @@ -35,7 +35,7 @@ public @interface DeclareParents { * public methods of the interface). */ Class defaultImpl() default DeclareParents.class; - + // note - a default of "null" is not allowed, // hence the strange default given above. } diff --git a/tests/bugs150/pr117681/MoodIndicator.java b/tests/bugs150/pr117681/MoodIndicator.java index ec420ad86..c6e47e1f3 100644 --- a/tests/bugs150/pr117681/MoodIndicator.java +++ b/tests/bugs150/pr117681/MoodIndicator.java @@ -23,8 +23,8 @@ public class MoodIndicator { // here is the actual ITD syntax when using @AspectJ // public static is mandatory // the field type must be the introduced interface. It can't be a class. - @DeclareParents("C") - public static Moody introduced = new MoodyImpl(); + @DeclareParents(value="C", defaultImpl=MoodyImpl.class) + Moody introduced; // @Before("execution(* *.*(..)) && this(m)") // public void feelingMoody(Moody m) { diff --git a/tests/bugs150/pr117681/TestAspect.java b/tests/bugs150/pr117681/TestAspect.java index 331677476..9657d6cd5 100644 --- a/tests/bugs150/pr117681/TestAspect.java +++ b/tests/bugs150/pr117681/TestAspect.java @@ -2,6 +2,6 @@ import org.aspectj.lang.annotation.*; @Aspect public class TestAspect { - @DeclareParents("Test") - public static Audit introduced = new AuditImpl(); + @DeclareParents(value="Test", defaultImpl=AuditImpl.class) + Audit introduced; } diff --git a/tests/java5/ataspectj/ataspectj/DeclareParentsImplementsReweavableTest.java b/tests/java5/ataspectj/ataspectj/DeclareParentsImplementsReweavableTest.java index 5e1a7d3c0..fad0d8488 100644 --- a/tests/java5/ataspectj/ataspectj/DeclareParentsImplementsReweavableTest.java +++ b/tests/java5/ataspectj/ataspectj/DeclareParentsImplementsReweavableTest.java @@ -39,8 +39,9 @@ public class DeclareParentsImplementsReweavableTest extends TestCase { @Aspect static class TestAspect { - @DeclareParents("ataspectj.DeclareParentsImplementsReweavableTest.Target") - public static I1 i1 = new Imp1(); + @DeclareParents(value="ataspectj.DeclareParentsImplementsReweavableTest.Target", + defaultImpl = Imp1.class) + public static I1 i1; } public void testDecPInt() { diff --git a/tests/java5/ataspectj/ataspectj/DeclareParentsImplementsReweavableTestAspect.java b/tests/java5/ataspectj/ataspectj/DeclareParentsImplementsReweavableTestAspect.java index c75585f75..60a6ca42f 100644 --- a/tests/java5/ataspectj/ataspectj/DeclareParentsImplementsReweavableTestAspect.java +++ b/tests/java5/ataspectj/ataspectj/DeclareParentsImplementsReweavableTestAspect.java @@ -20,7 +20,10 @@ import org.aspectj.lang.annotation.DeclareParents; @Aspect public class DeclareParentsImplementsReweavableTestAspect { - @DeclareParents("ataspectj.DeclareParentsImplementsReweavableTest.Target") - public static DeclareParentsImplementsReweavableTest.I2 i2 = new DeclareParentsImplementsReweavableTest.Imp2(); + @DeclareParents( + value="ataspectj.DeclareParentsImplementsReweavableTest.Target", + defaultImpl = DeclareParentsImplementsReweavableTest.Imp2.class + ) + public static DeclareParentsImplementsReweavableTest.I2 i2; } diff --git a/tests/java5/ataspectj/ataspectj/DeclareParentsImplementsTest.java b/tests/java5/ataspectj/ataspectj/DeclareParentsImplementsTest.java index 8b701a28e..b4cc9ed4e 100644 --- a/tests/java5/ataspectj/ataspectj/DeclareParentsImplementsTest.java +++ b/tests/java5/ataspectj/ataspectj/DeclareParentsImplementsTest.java @@ -50,10 +50,11 @@ public class DeclareParentsImplementsTest extends TestCase { @Aspect static class TestAspect { - @DeclareParents("ataspectj.DeclareParentsImplementsTest.Target") - public static Introduced i = new Implementation();//see here control of instantiation + @DeclareParents(value="ataspectj.DeclareParentsImplementsTest.Target", + defaultImpl=Implementation.class) + public static Introduced i; // will lead to: class Target implements Introduced { - // void intro(args) { TestAspect.i.intro(args); } + // void intro(args) { delegate to some hidden field, lazy initialized here for now } // } @Before("execution(* ataspectj.DeclareParentsImplementsTest.Introduced.intro())") diff --git a/tests/java5/ataspectj/ataspectj/DeclareParentsInterfaceTest.java b/tests/java5/ataspectj/ataspectj/DeclareParentsInterfaceTest.java index ffac0e4a2..2823251e5 100644 --- a/tests/java5/ataspectj/ataspectj/DeclareParentsInterfaceTest.java +++ b/tests/java5/ataspectj/ataspectj/DeclareParentsInterfaceTest.java @@ -15,6 +15,7 @@ import junit.framework.TestCase; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.DeclareImplements; +import org.aspectj.lang.annotation.DeclareParents; import java.util.Arrays; @@ -34,7 +35,7 @@ public class DeclareParentsInterfaceTest extends TestCase { @Aspect static class TestAspect { - @DeclareImplements("ataspectj.DeclareParentsInterfaceTest.Target") + @DeclareParents("ataspectj.DeclareParentsInterfaceTest.Target") Marker introduce; @Before("execution(* ataspectj.DeclareParentsInterfaceTest.Marker+.target())") diff --git a/tests/java5/decps/Basic1.java b/tests/java5/decps/Basic1.java new file mode 100644 index 000000000..d1fe8ea9d --- /dev/null +++ b/tests/java5/decps/Basic1.java @@ -0,0 +1,18 @@ +public class Basic1 { + public static void main(String []argv) { + Basic1 b = new Basic1(); + if (!(b instanceof X.I)) throw new RuntimeException("Basic1 should implement I"); + } +} + + + +aspect X { + + interface I { + } + + declare parents: Basic1 implements I; + +} + diff --git a/tests/java5/decps/Basic1b.java b/tests/java5/decps/Basic1b.java new file mode 100644 index 000000000..46e4e9bfb --- /dev/null +++ b/tests/java5/decps/Basic1b.java @@ -0,0 +1,22 @@ +import org.aspectj.lang.annotation.*; + +public class Basic1b { + public static void main(String []argv) { + Basic1b b = new Basic1b(); + if (!(b instanceof X.I)) throw new RuntimeException("Basic1b should implement I"); + } +} + + + +@Aspect +class X { + + interface I { + } + + @DeclareParents("Basic1b") + private I someField; + +} + diff --git a/tests/java5/decps/Basic2.java b/tests/java5/decps/Basic2.java new file mode 100644 index 000000000..5e14eb50a --- /dev/null +++ b/tests/java5/decps/Basic2.java @@ -0,0 +1,27 @@ +public class Basic2 { + public static void main(String []argv) { + Basic2 b = new Basic2(); + if (!(b instanceof X.I)) throw new RuntimeException("Basic2 should implement I"); + } +} + + + +aspect X { + + interface I { + } + + public void I.m2() { + + } + + + declare parents: Basic2 implements I; + + + before(): execution(* *(..)) { + } + +} + diff --git a/tests/java5/decps/Basic2b.java b/tests/java5/decps/Basic2b.java new file mode 100644 index 000000000..03c88f80d --- /dev/null +++ b/tests/java5/decps/Basic2b.java @@ -0,0 +1,30 @@ +import org.aspectj.lang.annotation.*; + +public class Basic2b { + public static void main(String []argv) { + Basic2b b = new Basic2b(); + if (!(b instanceof X.I)) throw new RuntimeException("Basic2b should implement I"); + } +} + + + +@Aspect class X { + + interface I { + } + + static class IImpl implements I { + public void m2() { } + } + + + @DeclareParents(value="Basic2b",defaultImpl=X.IImpl.class) + private I simplefield;; + + + @Before("execution(* *(..))") + public void advice1() {} + +} + diff --git a/tests/java5/decps/Basic3.java b/tests/java5/decps/Basic3.java new file mode 100644 index 000000000..868bbcdff --- /dev/null +++ b/tests/java5/decps/Basic3.java @@ -0,0 +1,33 @@ + + +public class Basic3 { + public static void main(String []argv) { + Basic3 b = new Basic3(); + if (!(b instanceof X.I)) throw new RuntimeException("Basic3 should implement I"); + ((X.I)b).m2(); + ((X.I)b).m3(); + ((X.I)b).m2(); + ((X.I)b).m4(); + } +} + + + +aspect X { + + interface I { + } + + public void I.m2() { } + public void I.m3() { } + public void I.m4() { } + + + declare parents: Basic3 implements I; + + + before(): call(* m*(..)) { + } + +} + diff --git a/tests/java5/decps/Basic3b.java b/tests/java5/decps/Basic3b.java new file mode 100644 index 000000000..1d4ecfe5a --- /dev/null +++ b/tests/java5/decps/Basic3b.java @@ -0,0 +1,39 @@ +import org.aspectj.lang.annotation.*; + +public class Basic3b { + public static void main(String []argv) { + Basic3b b = new Basic3b(); + if (!(b instanceof X.I)) throw new RuntimeException("Basic3b should implement I"); + ((X.I)b).m2(); + ((X.I)b).m3(); + ((X.I)b).m2(); + ((X.I)b).m4(); + } +} + + + +@Aspect class X { + + interface I { + public void m2(); + public void m3(); + public void m4(); + } + + static class IImpl implements I { + public void m2() { } + public void m3() { } + public void m4() { } + } + + + @DeclareParents(value="Basic3b",defaultImpl=IImpl.class) + private I simplefield; + + + @Before("call(* *(..))") + public void advice1() {} + +} + diff --git a/tests/java5/decps/Basic3c.java b/tests/java5/decps/Basic3c.java new file mode 100644 index 000000000..f050054e4 --- /dev/null +++ b/tests/java5/decps/Basic3c.java @@ -0,0 +1,39 @@ +import org.aspectj.lang.annotation.*; + +public class Basic3c { + public static void main(String []argv) { + Basic3c b = new Basic3c(); + if (!(b instanceof X.I)) throw new RuntimeException("Basic3c should implement I"); + ((X.I)b).m2(); + ((X.I)b).m3(); + ((X.I)b).m2(); + ((X.I)b).m4(); + } +} + + + +@Aspect class X { + + interface I { + public void m2(); + public void m3(); + public void m4(); + } + + class IImpl implements I { + public void m2() { } + public void m3() { } + public void m4() { } + } + + + @DeclareParents(value="Basic3c",defaultImpl=IImpl.class) + private I simplefield; + + + @Before("call(* *(..))") + public void advice1() {} + +} + diff --git a/tests/ltw/aop-abstractaspect.xml b/tests/ltw/aop-abstractaspect.xml index 7f82c94ee..00d541d5b 100644 --- a/tests/ltw/aop-abstractaspect.xml +++ b/tests/ltw/aop-abstractaspect.xml @@ -5,4 +5,4 @@ - + diff --git a/tests/src/org/aspectj/systemtest/ajc150/Ajc150Tests.java b/tests/src/org/aspectj/systemtest/ajc150/Ajc150Tests.java index 2382d8ac8..75bb203f3 100644 --- a/tests/src/org/aspectj/systemtest/ajc150/Ajc150Tests.java +++ b/tests/src/org/aspectj/systemtest/ajc150/Ajc150Tests.java @@ -41,6 +41,14 @@ public class Ajc150Tests extends org.aspectj.testing.XMLBasedAjcTestCase { protected File getSpecFile() { return new File("../tests/src/org/aspectj/systemtest/ajc150/ajc150.xml"); } + public void testDecps1() { runTest("decps - 1");} + public void testDecps1b() { runTest("decps - 1b");} + public void testDecps2() { runTest("decps - 2");} + public void testDecps2b() { runTest("decps - 2b");} + public void testDecps3() { runTest("decps - 3");} + public void testDecps3b() { runTest("decps - 3b");} + public void testDecps3c() { runTest("decps - 3c");} + public void testVarargsNPE_pr120826() { runTest("varargs NPE");} public void testNamedPointcutPertarget_pr120521() { runTest("named pointcut not resolved in pertarget pointcut");} public void testDollarClasses_pr120474() { runTest("Dollar classes");} diff --git a/tests/src/org/aspectj/systemtest/ajc150/ajc150.xml b/tests/src/org/aspectj/systemtest/ajc150/ajc150.xml index 0f6a75198..7115d779e 100644 --- a/tests/src/org/aspectj/systemtest/ajc150/ajc150.xml +++ b/tests/src/org/aspectj/systemtest/ajc150/ajc150.xml @@ -97,6 +97,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/weaver/src/org/aspectj/weaver/AjcMemberMaker.java b/weaver/src/org/aspectj/weaver/AjcMemberMaker.java index 978f80ffd..a0add374c 100644 --- a/weaver/src/org/aspectj/weaver/AjcMemberMaker.java +++ b/weaver/src/org/aspectj/weaver/AjcMemberMaker.java @@ -499,8 +499,18 @@ public class AjcMemberMaker { NameMangler.postIntroducedConstructor(aspectType, targetType), UnresolvedType.insert(targetType, paramTypes)); } - - public static ResolvedMember interConstructor(ResolvedType targetType, ResolvedMember constructor, UnresolvedType aspectType) { + + public static ResolvedMember itdAtDeclareParentsField(ResolvedType targetType, UnresolvedType itdType, UnresolvedType aspectType) { + return new ResolvedMemberImpl( + Member.FIELD, + targetType, + Modifier.PRIVATE, + itdType, + NameMangler.itdAtDeclareParentsField(aspectType, itdType), + null); + } + + public static ResolvedMember interConstructor(ResolvedType targetType, ResolvedMember constructor, UnresolvedType aspectType) { // // ResolvedType targetType, // UnresolvedType[] argTypes, diff --git a/weaver/src/org/aspectj/weaver/MethodDelegateTypeMunger.java b/weaver/src/org/aspectj/weaver/MethodDelegateTypeMunger.java index e7bc20d3b..fbfccd606 100644 --- a/weaver/src/org/aspectj/weaver/MethodDelegateTypeMunger.java +++ b/weaver/src/org/aspectj/weaver/MethodDelegateTypeMunger.java @@ -28,10 +28,12 @@ import org.aspectj.weaver.patterns.TypePattern; */ public class MethodDelegateTypeMunger extends ResolvedTypeMunger { + private final UnresolvedType aspect; + /** - * The field in the aspect that hosts the mixin instance + * The mixin impl (no arg ctor) */ - private final ResolvedMember aspectFieldDelegate; + private final String implClassName; /** * Type pattern this munger applies to @@ -43,52 +45,42 @@ public class MethodDelegateTypeMunger extends ResolvedTypeMunger { * * @param signature * @param aspect - * @param fieldName + * @param implClassName * @param typePattern */ - public MethodDelegateTypeMunger(ResolvedMember signature, ResolvedType aspect, String fieldName, TypePattern typePattern) { + public MethodDelegateTypeMunger(ResolvedMember signature, UnresolvedType aspect, String implClassName, TypePattern typePattern) { super(MethodDelegate, signature); + this.aspect = aspect; this.typePattern = typePattern; - - ResolvedMember[] fields = aspect.getDeclaredFields();//note: will unpack attributes - ResolvedMember field = null; - for (int i = 0; i < fields.length; i++) { - if (fieldName.equals(fields[i].getName())) { - field = fields[i]; - break; - } - } - if (field == null) { - throw new RuntimeException("Should not happen: aspect field not found for @DeclareParents delegate"); - } else { - aspectFieldDelegate = field; - } + this.implClassName = implClassName; } - private MethodDelegateTypeMunger(ResolvedMember signature, ResolvedMember fieldDelegate, TypePattern typePattern) { - super(MethodDelegate, signature); - this.aspectFieldDelegate = fieldDelegate; - this.typePattern = typePattern; + public ResolvedMember getDelegate(ResolvedType targetType) { + return AjcMemberMaker.itdAtDeclareParentsField( + targetType, + signature.getDeclaringType(), + aspect + ); } - public ResolvedMember getDelegate() { - return aspectFieldDelegate; + public String getImplClassName() { + return implClassName; } public void write(DataOutputStream s) throws IOException { kind.write(s); signature.write(s); - aspectFieldDelegate.write(s); + aspect.write(s); + s.writeUTF(implClassName); typePattern.write(s); } - - public static ResolvedTypeMunger readMethod(VersionedDataInputStream s, ISourceContext context) throws IOException { ResolvedMemberImpl signature = ResolvedMemberImpl.readResolvedMember(s, context); - ResolvedMemberImpl field = ResolvedMemberImpl.readResolvedMember(s, context); + UnresolvedType aspect = UnresolvedType.read(s); + String implClassName = s.readUTF(); TypePattern tp = TypePattern.read(s, context); - return new MethodDelegateTypeMunger(signature, field, tp); + return new MethodDelegateTypeMunger(signature, aspect, implClassName, tp); } /** @@ -115,4 +107,62 @@ public class MethodDelegateTypeMunger extends ResolvedTypeMunger { public boolean changesPublicSignature() { return true; } + + public static class FieldHostTypeMunger extends ResolvedTypeMunger { + + private UnresolvedType aspect; + + /** + * Type pattern this munger applies to + */ + private final TypePattern typePattern; + + /** + * Construct a new type munger for @AspectJ ITD + * + * @param field + * @param aspect + * @param typePattern + */ + public FieldHostTypeMunger(ResolvedMember field, UnresolvedType aspect, TypePattern typePattern) { + super(FieldHost, field); + this.aspect = aspect; + this.typePattern = typePattern; + } + + public void write(DataOutputStream s) throws IOException { + kind.write(s); + signature.write(s); + aspect.write(s); + typePattern.write(s); + } + + public static ResolvedTypeMunger readFieldHost(VersionedDataInputStream s, ISourceContext context) throws IOException { + ResolvedMemberImpl signature = ResolvedMemberImpl.readResolvedMember(s, context); + UnresolvedType aspect = UnresolvedType.read(s); + TypePattern tp = TypePattern.read(s, context); + return new FieldHostTypeMunger(signature, aspect, tp); + } + + /** + * Match based on given type pattern, only classes can be matched + * + * @param matchType + * @param aspectType + * @return true if match + */ + public boolean matches(ResolvedType matchType, ResolvedType aspectType) { + // match only on class + if (matchType.isEnum() || matchType.isInterface() || matchType.isAnnotation()) { + return false; + } + + return typePattern.matchesStatically(matchType); + } + + public boolean changesPublicSignature() { + return false; + } + + } } diff --git a/weaver/src/org/aspectj/weaver/NameMangler.java b/weaver/src/org/aspectj/weaver/NameMangler.java index 17a29a528..4dfd751b9 100644 --- a/weaver/src/org/aspectj/weaver/NameMangler.java +++ b/weaver/src/org/aspectj/weaver/NameMangler.java @@ -64,16 +64,17 @@ public class NameMangler { // PTWIMPL method names that must include aspect type public static String perTypeWithinFieldForTarget(UnresolvedType aspectType) { - String s = makeName(aspectType.getNameAsIdentifier(), "ptwAspectInstance"); - return s; + return makeName(aspectType.getNameAsIdentifier(), "ptwAspectInstance"); } - - public static String perTypeWithinLocalAspectOf(UnresolvedType aspectType) { + + public static String perTypeWithinLocalAspectOf(UnresolvedType aspectType) { return makeName(aspectType.getNameAsIdentifier(), "localAspectOf"); } - - + public static String itdAtDeclareParentsField(UnresolvedType aspectType, UnresolvedType itdType) { + return makeName(aspectType.getNameAsIdentifier(), itdType.getNameAsIdentifier()); + } + public static String privilegedAccessMethodForMethod(String name, UnresolvedType objectType, UnresolvedType aspectType) { return makeName("privMethod", aspectType.getNameAsIdentifier(), objectType.getNameAsIdentifier(), name); diff --git a/weaver/src/org/aspectj/weaver/ResolvedTypeMunger.java b/weaver/src/org/aspectj/weaver/ResolvedTypeMunger.java index 0e95d39c5..5891b9bc8 100644 --- a/weaver/src/org/aspectj/weaver/ResolvedTypeMunger.java +++ b/weaver/src/org/aspectj/weaver/ResolvedTypeMunger.java @@ -135,6 +135,8 @@ public abstract class ResolvedTypeMunger { return NewConstructorTypeMunger.readConstructor(s, context); } else if (kind == MethodDelegate) { return MethodDelegateTypeMunger.readMethod(s, context); + } else if (kind == FieldHost) { + return MethodDelegateTypeMunger.FieldHostTypeMunger.readFieldHost(s, context); } else { throw new RuntimeException("unimplemented"); } @@ -237,12 +239,14 @@ public abstract class ResolvedTypeMunger { case 2: return Method; case 5: return Constructor; case 9: return MethodDelegate; + case 10: return FieldHost; } throw new BCException("bad kind: " + key); } public String toString() { // we want MethodDelegate to appear as Method in WeaveInfo messages + //TODO we may want something for fieldhost ? if (MethodDelegate.getName().equals(getName())) { return Method.toString(); } else { @@ -267,6 +271,7 @@ public abstract class ResolvedTypeMunger { public static final Kind AnnotationOnType = new Kind("AnnotationOnType",8); // not serialized public static final Kind MethodDelegate = new Kind("MethodDelegate", 9);// serialized, @AJ ITDs + public static final Kind FieldHost = new Kind("FieldHost", 10);// serialized, @AJ ITDs public static final String SUPER_DISPATCH_NAME = "superDispatch"; diff --git a/weaver/src/org/aspectj/weaver/bcel/AtAjAttributes.java b/weaver/src/org/aspectj/weaver/bcel/AtAjAttributes.java index e07f44c42..9297f1d16 100644 --- a/weaver/src/org/aspectj/weaver/bcel/AtAjAttributes.java +++ b/weaver/src/org/aspectj/weaver/bcel/AtAjAttributes.java @@ -17,6 +17,7 @@ import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; +import java.lang.reflect.Modifier; import org.aspectj.apache.bcel.Constants; import org.aspectj.apache.bcel.classfile.Attribute; @@ -31,6 +32,7 @@ import org.aspectj.apache.bcel.classfile.annotation.Annotation; import org.aspectj.apache.bcel.classfile.annotation.ElementNameValuePair; import org.aspectj.apache.bcel.classfile.annotation.RuntimeAnnotations; import org.aspectj.apache.bcel.classfile.annotation.RuntimeVisibleAnnotations; +import org.aspectj.apache.bcel.classfile.annotation.ClassElementValue; import org.aspectj.apache.bcel.generic.Type; import org.aspectj.bridge.IMessage; import org.aspectj.bridge.IMessageHandler; @@ -50,6 +52,9 @@ import org.aspectj.weaver.ResolvedPointcutDefinition; import org.aspectj.weaver.ResolvedType; import org.aspectj.weaver.UnresolvedType; import org.aspectj.weaver.WeaverMessages; +import org.aspectj.weaver.NewFieldTypeMunger; +import org.aspectj.weaver.ResolvedMemberImpl; +import org.aspectj.weaver.Member; import org.aspectj.weaver.patterns.AndPointcut; import org.aspectj.weaver.patterns.DeclareErrorOrWarning; import org.aspectj.weaver.patterns.DeclareParents; @@ -317,7 +322,6 @@ public class AtAjAttributes { if (acceptAttribute(fattribute)) { RuntimeAnnotations frvs = (RuntimeAnnotations) fattribute; if (handleDeclareErrorOrWarningAnnotation(frvs, fstruct) - || handleDeclareImplementsAnnotation(frvs, fstruct) || handleDeclareParentsAnnotation(frvs, fstruct)) { // semantic check - must be in an @Aspect [remove if previous block bypassed in advance] if (!type.isAnnotationStyleAspect()) { @@ -338,7 +342,7 @@ public class AtAjAttributes { } struct.ajAttributes.addAll(fstruct.ajAttributes); } - + return struct.ajAttributes; } @@ -463,8 +467,8 @@ public class AtAjAttributes { // Note: field annotation are for ITD and DEOW - processed at class level directly return Collections.EMPTY_LIST; } - - + + /** * Read @Aspect * @@ -518,12 +522,12 @@ public class AtAjAttributes { struct.context, bindings ); - + // // we can't resolve here since the perclause typically refers to pointcuts // // defined in the aspect that we haven't told the BcelObjectType about yet. -// +// // perClause.resolve(binding); - + // so we prepare to do it later... aspectAttribute.setResolutionScope(binding); return true; @@ -607,47 +611,47 @@ public class AtAjAttributes { return false; } - /** - * Read @DeclareImplements - * - * @param runtimeAnnotations - * @param struct - * @return true if found - */ - private static boolean handleDeclareImplementsAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeFieldStruct struct) {//, ResolvedPointcutDefinition preResolvedPointcut) { - Annotation deci = getAnnotation(runtimeAnnotations, AjcMemberMaker.DECLAREIMPLEMENTS_ANNOTATION); - if (deci != null) { - ElementNameValuePair deciPatternNVP = getAnnotationElement(deci, VALUE); - String deciPattern = deciPatternNVP.getValue().stringifyValue(); - if (deciPattern != null) { - TypePattern typePattern = parseTypePattern(deciPattern, struct); - ResolvedType fieldType = UnresolvedType.forSignature(struct.field.getSignature()).resolve(struct.enclosingType.getWorld()); - if (fieldType.isPrimitiveType()) { - return false; - } else if (fieldType.isInterface()) { - TypePattern parent = new ExactTypePattern(UnresolvedType.forSignature(struct.field.getSignature()), false, false); - parent.resolve(struct.enclosingType.getWorld()); - List parents = new ArrayList(1); - parents.add(parent); - //TODO kick ISourceLocation sl = struct.bField.getSourceLocation(); ?? - struct.ajAttributes.add( - new AjAttribute.DeclareAttribute( - new DeclareParents( - typePattern, - parents, - false - ) - ) - ); - return true; - } else { - reportError("@DeclareImplements: can only be used on field whose type is an interface", struct); - return false; - } - } - } - return false; - } +// /** +// * Read @DeclareImplements +// * +// * @param runtimeAnnotations +// * @param struct +// * @return true if found +// */ +// private static boolean handleDeclareImplementsAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeFieldStruct struct) {//, ResolvedPointcutDefinition preResolvedPointcut) { +// Annotation deci = getAnnotation(runtimeAnnotations, AjcMemberMaker.DECLAREIMPLEMENTS_ANNOTATION); +// if (deci != null) { +// ElementNameValuePair deciPatternNVP = getAnnotationElement(deci, VALUE); +// String deciPattern = deciPatternNVP.getValue().stringifyValue(); +// if (deciPattern != null) { +// TypePattern typePattern = parseTypePattern(deciPattern, struct); +// ResolvedType fieldType = UnresolvedType.forSignature(struct.field.getSignature()).resolve(struct.enclosingType.getWorld()); +// if (fieldType.isPrimitiveType()) { +// return false; +// } else if (fieldType.isInterface()) { +// TypePattern parent = new ExactTypePattern(UnresolvedType.forSignature(struct.field.getSignature()), false, false); +// parent.resolve(struct.enclosingType.getWorld()); +// List parents = new ArrayList(1); +// parents.add(parent); +// //TODO kick ISourceLocation sl = struct.bField.getSourceLocation(); ?? +// struct.ajAttributes.add( +// new AjAttribute.DeclareAttribute( +// new DeclareParents( +// typePattern, +// parents, +// false +// ) +// ) +// ); +// return true; +// } else { +// reportError("@DeclareImplements: can only be used on field whose type is an interface", struct); +// return false; +// } +// } +// } +// return false; +// } /** * Read @DeclareParents @@ -664,9 +668,7 @@ public class AtAjAttributes { if (decpPattern != null) { TypePattern typePattern = parseTypePattern(decpPattern, struct); ResolvedType fieldType = UnresolvedType.forSignature(struct.field.getSignature()).resolve(struct.enclosingType.getWorld()); - if (fieldType.isPrimitiveType()) { - return false; - } else if (fieldType.isInterface() && (struct.field.isPublic() && struct.field.isStatic())) { + if (fieldType.isInterface()) { TypePattern parent = new ExactTypePattern(UnresolvedType.forSignature(struct.field.getSignature()), false, false); parent.resolve(struct.enclosingType.getWorld()); //TODO kick ISourceLocation sl = struct.bField.getSourceLocation(); ?? @@ -681,25 +683,66 @@ public class AtAjAttributes { ) ) ); + + + // do we have a defaultImpl=xxx.class (ie implementation) + String defaultImplClassName = null; + ElementNameValuePair defaultImplNVP = getAnnotationElement(decp, "defaultImpl"); + if (defaultImplNVP != null) { + ClassElementValue defaultImpl = (ClassElementValue) defaultImplNVP.getValue(); + defaultImplClassName = UnresolvedType.forSignature(defaultImpl.getClassString()).getName(); + if (defaultImplClassName.equals("org.aspectj.lang.annotation.DeclareParents")) { + defaultImplClassName = null; + } + //TODO check public no arg ctor + } + // then iterate on field interface hierarchy (not object) - for (Iterator it = fieldType.getMethods(); it.hasNext();) { - ResolvedMember method = (ResolvedMember)it.next(); + boolean hasAtLeastOneMethod = false; + ResolvedMember[] methods = (ResolvedMember[])fieldType.getMethodsWithoutIterator(true, false).toArray(new ResolvedMember[0]); + for (int i = 0; i < methods.length; i++) { + ResolvedMember method = (ResolvedMember)methods[i]; if (method.isAbstract()) { + if (defaultImplClassName == null) { + // non marker interface with no default impl provided + reportError("@DeclareParents: used with a non marker interface and no defaultImpl=\"...\" provided", struct); + return false; + } + hasAtLeastOneMethod = true; + struct.ajAttributes.add( new AjAttribute.TypeMunger( new MethodDelegateTypeMunger( method, struct.enclosingType, - struct.field.getName(), + defaultImplClassName, typePattern ) ) ); } } + // successfull so far, we thus need a bcel type munger to have + // a field hosting the mixin in the target type + if (hasAtLeastOneMethod) { + struct.ajAttributes.add( + new AjAttribute.TypeMunger( + new MethodDelegateTypeMunger.FieldHostTypeMunger( + AjcMemberMaker.itdAtDeclareParentsField( + null,//prototyped + fieldType, + struct.enclosingType + ), + struct.enclosingType, + typePattern + ) + ) + ); + } + return true; } else { - reportError("@DeclareParents: can only be used on a public static field whose type is an interface", struct); + reportError("@DeclareParents: can only be used on a field whose type is an interface", struct); return false; } } diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelTypeMunger.java b/weaver/src/org/aspectj/weaver/bcel/BcelTypeMunger.java index 9bbd0d49e..46332675a 100644 --- a/weaver/src/org/aspectj/weaver/bcel/BcelTypeMunger.java +++ b/weaver/src/org/aspectj/weaver/bcel/BcelTypeMunger.java @@ -29,6 +29,7 @@ import org.aspectj.apache.bcel.generic.InstructionFactory; import org.aspectj.apache.bcel.generic.InstructionHandle; import org.aspectj.apache.bcel.generic.InstructionList; import org.aspectj.apache.bcel.generic.Type; +import org.aspectj.apache.bcel.generic.BranchInstruction; import org.aspectj.apache.bcel.generic.annotation.AnnotationGen; import org.aspectj.bridge.IMessage; import org.aspectj.bridge.ISourceLocation; @@ -63,7 +64,7 @@ import org.aspectj.weaver.WeaverStateInfo; import org.aspectj.weaver.World; import org.aspectj.weaver.patterns.DeclareAnnotation; import org.aspectj.weaver.patterns.Pointcut; - +import org.aspectj.lang.Signature; //XXX addLazyMethodGen is probably bad everywhere public class BcelTypeMunger extends ConcreteTypeMunger { @@ -87,6 +88,8 @@ public class BcelTypeMunger extends ConcreteTypeMunger { changed = mungeNewMethod(weaver, (NewMethodTypeMunger)munger); } else if (munger.getKind() == ResolvedTypeMunger.MethodDelegate) { changed = mungeMethodDelegate(weaver, (MethodDelegateTypeMunger)munger); + } else if (munger.getKind() == ResolvedTypeMunger.FieldHost) { + changed = mungeFieldHost(weaver, (MethodDelegateTypeMunger.FieldHostTypeMunger)munger); } else if (munger.getKind() == ResolvedTypeMunger.PerObjectInterface) { changed = mungePerObjectInterface(weaver, (PerObjectInterfaceTypeMunger)munger); worthReporting = false; @@ -147,7 +150,9 @@ public class BcelTypeMunger extends ConcreteTypeMunger { // reportDeclareParentsMessage(WeaveMessage.WEAVEMESSAGE_DECLAREPARENTSEXTENDS,sourceType,parent); } - } else { + } else if (munger.getKind().equals(ResolvedTypeMunger.FieldHost)) { + ;//hidden + } else { ResolvedMember declaredSig = munger.getDeclaredSignature(); if (declaredSig==null) declaredSig= munger.getSignature(); weaver.getWorld().getMessageHandler().handleMessage(WeaveMessage.constructWeavingMessage(WeaveMessage.WEAVEMESSAGE_ITD, @@ -1103,11 +1108,23 @@ public class BcelTypeMunger extends ConcreteTypeMunger { InstructionList body = new InstructionList(); InstructionFactory fact = gen.getFactory(); - // getstatic field from aspect - body.append(Utility.createGet(fact, munger.getDelegate())); - + // getfield + body.append(InstructionConstants.ALOAD_0); + body.append(Utility.createGet(fact, munger.getDelegate(weaver.getLazyClassGen().getType()))); + BranchInstruction ifNonNull = InstructionFactory.createBranchInstruction(Constants.IFNULL, null); + body.append(ifNonNull); + InstructionHandle ifNonNullElse = body.append(InstructionConstants.ALOAD_0); + body.append(fact.createNew(munger.getImplClassName())); + body.append(InstructionConstants.DUP); + body.append(fact.createInvoke(munger.getImplClassName(), "", Type.VOID, Type.NO_ARGS, Constants.INVOKESPECIAL)); + body.append(Utility.createSet(fact, munger.getDelegate(weaver.getLazyClassGen().getType()))); + ifNonNull.setTarget(ifNonNullElse); + body.append(InstructionConstants.ALOAD_0); + body.append(Utility.createGet(fact, munger.getDelegate(weaver.getLazyClassGen().getType()))); + + //args int pos = 0; - if (!introduced.isStatic()) { // skip 'this' + if (!introduced.isStatic()) { // skip 'this' (?? can this really happen) //body.append(InstructionFactory.createThis()); pos++; } @@ -1133,7 +1150,25 @@ public class BcelTypeMunger extends ConcreteTypeMunger { return false; } - private ResolvedMember getRealMemberForITDFromAspect(ResolvedType aspectType,ResolvedMember lookingFor,boolean isCtorRelated) { + private boolean mungeFieldHost(BcelClassWeaver weaver, MethodDelegateTypeMunger.FieldHostTypeMunger munger) { + LazyClassGen gen = weaver.getLazyClassGen(); + if (gen.getType().isAnnotation() || gen.getType().isEnum()) { + // don't signal error as it could be a consequence of a wild type pattern + return false; + } + boolean shouldApply = munger.matches(weaver.getLazyClassGen().getType(), aspectType); + ResolvedMember host = AjcMemberMaker.itdAtDeclareParentsField( + weaver.getLazyClassGen().getType(), + munger.getSignature().getType(), + aspectType); + weaver.getLazyClassGen().addField(makeFieldGen( + weaver.getLazyClassGen(), + host).getField(), null); + return true; + } + + + private ResolvedMember getRealMemberForITDFromAspect(ResolvedType aspectType,ResolvedMember lookingFor,boolean isCtorRelated) { World world = aspectType.getWorld(); boolean debug = false; if (debug) {