+++ /dev/null
-/*******************************************************************************
- * 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();
-
-}
* The target types expression
*/
String value();
-
+
/**
* Optional class defining default implementation
* of interface members (equivalent to defining
* public methods of the interface).
*/
Class defaultImpl() default DeclareParents.class;
-
+
// note - a default of "null" is not allowed,
// hence the strange default given above.
}
// 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) {
@Aspect
public class TestAspect {
- @DeclareParents("Test")
- public static Audit introduced = new AuditImpl();
+ @DeclareParents(value="Test", defaultImpl=AuditImpl.class)
+ Audit introduced;
}
@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() {
@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;
}
@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())")
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;
@Aspect
static class TestAspect {
- @DeclareImplements("ataspectj.DeclareParentsInterfaceTest.Target")
+ @DeclareParents("ataspectj.DeclareParentsInterfaceTest.Target")
Marker introduce;
@Before("execution(* ataspectj.DeclareParentsInterfaceTest.Marker+.target())")
--- /dev/null
+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;
+
+}
+
--- /dev/null
+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;
+
+}
+
--- /dev/null
+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(* *(..)) {
+ }
+
+}
+
--- /dev/null
+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() {}
+
+}
+
--- /dev/null
+
+
+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*(..)) {
+ }
+
+}
+
--- /dev/null
+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() {}
+
+}
+
--- /dev/null
+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() {}
+
+}
+
<weaver options="-showWeaveInfo"/>
</aspectj>
-
+
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");}
<compile files="Pr114054.aj" options=""/>
<run class="Pr114054"/>
</ajc-test>
+
+
+ <ajc-test dir="java5/decps" title="decps - 1">
+ <compile files="Basic1.java" options="-1.5"/>
+ <run class="Basic1"/>
+ </ajc-test>
+
+ <ajc-test dir="java5/decps" title="decps - 1b">
+ <compile files="Basic1b.java" options="-1.5"/>
+ <run class="Basic1b"/>
+ </ajc-test>
+
+ <ajc-test dir="java5/decps" title="decps - 2">
+ <compile files="Basic2.java" options="-1.5 -showWeaveInfo">
+ <message kind="weave" text="Join point 'method-execution(void X$I.m2())' in Type 'X' (Basic2.java:15) advised by before advice from 'X' (Basic2.java:23)"/>
+ <message kind="weave" text="Type 'X$I' (Basic2.java) has intertyped method from 'X' (Basic2.java:'void X$I.m2()')"/>
+ <message kind="weave" text="Extending interface set for type 'Basic2' (Basic2.java) to include 'X$I' (Basic2.java)"/>
+ <message kind="weave" text="Type 'Basic2' (Basic2.java) has intertyped method from 'X' (Basic2.java:'void X$I.m2()')"/>
+ <message kind="weave" text="Join point 'method-execution(void Basic2.main(java.lang.String[]))' in Type 'Basic2' (Basic2.java:2) advised by before advice from 'X' (Basic2.java:23)"/>
+ </compile>
+ <run class="Basic2"/>
+ </ajc-test>
+
+ <ajc-test dir="java5/decps" title="decps - 2b">
+ <compile files="Basic2b.java" options="-1.5 -showWeaveInfo">
+ <message kind="weave" text="Join point 'method-execution(void X$IImpl.m2())' in Type 'X$IImpl' (Basic2b.java:18) advised by before advice from 'X' (Basic2b.java:27)"/>
+ <message kind="weave" text="Extending interface set for type 'Basic2b' (Basic2b.java) to include 'X$I' (Basic2b.java)"/>
+ <message kind="weave" text="Join point 'method-execution(void Basic2b.main(java.lang.String[]))' in Type 'Basic2b' (Basic2b.java:4) advised by before advice from 'X' (Basic2b.java:27)"/>
+ </compile>
+ <run class="Basic2b"/>
+ </ajc-test>
+
+ <ajc-test dir="java5/decps" title="decps - 3">
+ <compile files="Basic3.java" options="-1.5 -showWeaveInfo">
+ <message kind="weave" text="Extending interface set for type 'Basic3' (Basic3.java) to include 'X$I' (Basic3.java)"/>
+ <message kind="weave" text="Type 'Basic3' (Basic3.java) has intertyped method from 'X' (Basic3.java:'void X$I.m2()')"/>
+ <message kind="weave" text="Type 'Basic3' (Basic3.java) has intertyped method from 'X' (Basic3.java:'void X$I.m3()')"/>
+ <message kind="weave" text="Type 'Basic3' (Basic3.java) has intertyped method from 'X' (Basic3.java:'void X$I.m4()')"/>
+ <message kind="weave" text="Join point 'method-call(void X$I.m2())' in Type 'Basic3' (Basic3.java:7) advised by before advice from 'X' (Basic3.java:29)"/>
+ <message kind="weave" text="Join point 'method-call(void X$I.m3())' in Type 'Basic3' (Basic3.java:8) advised by before advice from 'X' (Basic3.java:29)"/>
+ <message kind="weave" text="Join point 'method-call(void X$I.m2())' in Type 'Basic3' (Basic3.java:9) advised by before advice from 'X' (Basic3.java:29)"/>
+ <message kind="weave" text="Join point 'method-call(void X$I.m4())' in Type 'Basic3' (Basic3.java:10) advised by before advice from 'X' (Basic3.java:29)"/>
+ <message kind="weave" text="Type 'X$I' (Basic3.java) has intertyped method from 'X' (Basic3.java:'void X$I.m2()')"/>
+ <message kind="weave" text="Type 'X$I' (Basic3.java) has intertyped method from 'X' (Basic3.java:'void X$I.m3()')"/>
+ <message kind="weave" text="Type 'X$I' (Basic3.java) has intertyped method from 'X' (Basic3.java:'void X$I.m4()')"/>
+ </compile>
+ <run class="Basic3"/>
+ </ajc-test>
+
+ <ajc-test dir="java5/decps" title="decps - 3b">
+ <compile files="Basic3b.java" options="-1.5 -showWeaveInfo">
+ <message kind="weave" text="Extending interface set for type 'Basic3b' (Basic3b.java) to include 'X$I' (Basic3b.java)"/>
+ <message kind="weave" text="Type 'Basic3b' (Basic3b.java) has intertyped method from 'X' (Basic3b.java:'void X$I.m2()')"/>
+ <message kind="weave" text="Type 'Basic3b' (Basic3b.java) has intertyped method from 'X' (Basic3b.java:'void X$I.m3()')"/>
+ <message kind="weave" text="Type 'Basic3b' (Basic3b.java) has intertyped method from 'X' (Basic3b.java:'void X$I.m4()')"/>
+ <message kind="weave" text="Join point 'method-call(void X$I.m2())' in Type 'Basic3b' (Basic3b.java:7) advised by before advice from 'X' (Basic3b.java:36)"/>
+ <message kind="weave" text="Join point 'method-call(void X$I.m3())' in Type 'Basic3b' (Basic3b.java:8) advised by before advice from 'X' (Basic3b.java:36)"/>
+ <message kind="weave" text="Join point 'method-call(void X$I.m2())' in Type 'Basic3b' (Basic3b.java:9) advised by before advice from 'X' (Basic3b.java:36)"/>
+ <message kind="weave" text="Join point 'method-call(void X$I.m4())' in Type 'Basic3b' (Basic3b.java:10) advised by before advice from 'X' (Basic3b.java:36)"/>
+ </compile>
+ <run class="Basic3b"/>
+ </ajc-test>
+
+ <ajc-test dir="java5/decps" title="decps - 3c">
+ <compile files="Basic3c.java" options="-1.5">
+ </compile>
+ <run class="Basic3c"/>
+ </ajc-test>
+
+
<ajc-test dir="bugs150/pr119570" pr="119570" title="spurious override method warning">
<compile files="NodeImpl.java,INode.java,ParameterizedDP.java" options="-1.5"/>
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,
*/
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
*
* @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);
}
/**
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;
+ }
+
+ }
}
// 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);
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");
}
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 {
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";
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;
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;
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;
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()) {
}
struct.ajAttributes.addAll(fstruct.ajAttributes);
}
-
+
return struct.ajAttributes;
}
// Note: field annotation are for ITD and DEOW - processed at class level directly
return Collections.EMPTY_LIST;
}
-
-
+
+
/**
* Read @Aspect
*
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;
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
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(); ??
)
)
);
+
+
+ // 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;
}
}
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;
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 {
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;
// 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,
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(), "<init>", 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++;
}
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) {