]> source.dussan.org Git - aspectj.git/commitdiff
merge of @DeclareParents fix from HEAD into 1.5.0 release branch
authoracolyer <acolyer>
Mon, 19 Dec 2005 14:22:04 +0000 (14:22 +0000)
committeracolyer <acolyer>
Mon, 19 Dec 2005 14:22:04 +0000 (14:22 +0000)
24 files changed:
aspectj5rt/java5-src/org/aspectj/lang/annotation/DeclareImplements.java [deleted file]
aspectj5rt/java5-src/org/aspectj/lang/annotation/DeclareParents.java
tests/bugs150/pr117681/MoodIndicator.java
tests/bugs150/pr117681/TestAspect.java
tests/java5/ataspectj/ataspectj/DeclareParentsImplementsReweavableTest.java
tests/java5/ataspectj/ataspectj/DeclareParentsImplementsReweavableTestAspect.java
tests/java5/ataspectj/ataspectj/DeclareParentsImplementsTest.java
tests/java5/ataspectj/ataspectj/DeclareParentsInterfaceTest.java
tests/java5/decps/Basic1.java [new file with mode: 0644]
tests/java5/decps/Basic1b.java [new file with mode: 0644]
tests/java5/decps/Basic2.java [new file with mode: 0644]
tests/java5/decps/Basic2b.java [new file with mode: 0644]
tests/java5/decps/Basic3.java [new file with mode: 0644]
tests/java5/decps/Basic3b.java [new file with mode: 0644]
tests/java5/decps/Basic3c.java [new file with mode: 0644]
tests/ltw/aop-abstractaspect.xml
tests/src/org/aspectj/systemtest/ajc150/Ajc150Tests.java
tests/src/org/aspectj/systemtest/ajc150/ajc150.xml
weaver/src/org/aspectj/weaver/AjcMemberMaker.java
weaver/src/org/aspectj/weaver/MethodDelegateTypeMunger.java
weaver/src/org/aspectj/weaver/NameMangler.java
weaver/src/org/aspectj/weaver/ResolvedTypeMunger.java
weaver/src/org/aspectj/weaver/bcel/AtAjAttributes.java
weaver/src/org/aspectj/weaver/bcel/BcelTypeMunger.java

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 (file)
index dbb1bf1..0000000
+++ /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();
-    
-}
index fe7267849153e1dd38209822ea64f5763b908d6d..b7c2452e29a09f0115ff34a1efcc360b79966d28 100644 (file)
@@ -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.
 }
index ec420ad86c97d4445dcca166b7711bb7bd0d5402..c6e47e1f3ea62a44b801f9a65d817163b7a2e1e0 100644 (file)
@@ -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) {
index 33167747673a1415369cdb10b4b68209a53adfb2..9657d6cd5bb64d648f6f293f375e07215364e880 100644 (file)
@@ -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;
 }
index 5e1a7d3c08d8e5fb6560603b540176fe4d8cd992..fad0d8488df387aac65d0b37ded56b1ae2f1aacc 100644 (file)
@@ -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() {
index c75585f75cb64e7d201a7a4dd367219c260bc456..60a6ca42f916a7bf4d20181691178cdd6c4e412c 100644 (file)
@@ -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;
 
 }
index 8b701a28e8d5b62f60cd4a2a10b16deab0389b5a..b4cc9ed4e4783ee9d03d4d4ec452fd7c1e0ed79b 100644 (file)
@@ -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())")
index ffac0e4a26d24654ccec0530b1e6594af041b626..2823251e564f9922bc9f733c4213a33b48e90584 100644 (file)
@@ -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 (file)
index 0000000..d1fe8ea
--- /dev/null
@@ -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 (file)
index 0000000..46e4e9b
--- /dev/null
@@ -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 (file)
index 0000000..5e14eb5
--- /dev/null
@@ -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 (file)
index 0000000..03c88f8
--- /dev/null
@@ -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 (file)
index 0000000..868bbcd
--- /dev/null
@@ -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 (file)
index 0000000..1d4ecfe
--- /dev/null
@@ -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 (file)
index 0000000..f050054
--- /dev/null
@@ -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() {}
+
+}
+  
index 7f82c94eea4cf66c3bc2f95b2ea733e7638875be..00d541d5b87335efb60e15f3eb9c69ef65037e94 100644 (file)
@@ -5,4 +5,4 @@
     
     <weaver options="-showWeaveInfo"/>
 </aspectj>
-       
+
index 2382d8ac8a99c3564d96910c967f1d7d05a0039b..75bb203f38c7599de072de6dd61f27c3fb9c55ab 100644 (file)
@@ -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");}
index 0f6a751983192ce0037c31b4db86859e91f5e4e6..7115d779e73b4364f2eeb3312901358a2b68398a 100644 (file)
      <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"/>
index 978f80ffd7e94ea906283333caca111c183d2857..a0add374c1fc55e41054bd7f51cbed8587ba8ef9 100644 (file)
@@ -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,
index e7bc20d3b7e85b63972e9786f9d70b0acebbb5b1..fbfccd6062b8fa02c5c68d104ba1b14354353e5e 100644 (file)
@@ -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;
+        }
+
+    }
 }
index 17a29a52810203aaf979d9be183427ca61b002f3..4dfd751b9577f40bf5c4ead1364aa25972f88ea9 100644 (file)
@@ -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);
index 0e95d39c54b5f8d61d7300aecb9605179502dca4..5891b9bc84fed3ffc71acadc8707d1c7c7c8b905 100644 (file)
@@ -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";
 
index e07f44c422c29ade0afd2954fb5a5fb644472ab1..9297f1d16819632965f4f062d9df89806c73cbe5 100644 (file)
@@ -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;
                 }
             }
index 9bbd0d49e07d5fad5f811a054b28b1da17d41d1d..46332675a547aca1c58fe84b14875414eb57a613 100644 (file)
@@ -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(), "<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++;
                }
@@ -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) {