Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[aspectj-users] @DeclareParents and "this" (try 2)

I apologize in advance for not replying to my original email, but the client I
have access to now doesn't have access to it.

In any case, I thought I'd provide concrete examples to illustrate the issues
I'm seeing.  Unfortunately, there are issues that make even showing the issues
problematic.  I'm using the latest development version of AspectJ.  What I want
to demonstrate is that "this" in an annotation-style declare parents is the
instance of the interface, not the instance of the target.  I'm not surprised
by this, but I have been unable to determine how to get the actual target in
the advice.

Whereas I'm playing with Hibernate/Spring/and AspectJ to demo a non-anemic
domain model, I'd intended to show this with clone(), where I'd thought clone
would return an instance if the Impl class and not a new instance of the target
class.  To illustrate, let me start with the "classic" example:

x/X.java
========
package x;

public class X {
   public static void x(Object o) {
      System.out.println("o's class is "+o.getClass().getName());
   }
}

classic/CClassAspect.aj
=======================
package classic;

import x.X;

public aspect CClassAspect {
   public interface CClassIfc extends Cloneable {
      void callX();
   }

   declare parents : classic.CClass implements CClassIfc;

   public Object CClassIfc.clone() throws CloneNotSupportedException {
      try { return this.getClass().newInstance(); } catch (Exception e) { throw
new CloneNotSupportedException(e.toString()); }
   }
   public void CClassIfc.callX() {
      X.x(this);
   }
}

classic/CClass.java
===================
package classic;

public class CClass {
   public static void main(String[] args) throws Exception {
      final CClass c = new CClass();
      System.out.println("Cloned object's class is
"+c.clone().getClass().getName());
      ((CClassAspect.CClassIfc) c).callX();
   }
}

Running CClass gives:
Cloned object's class is classic.CClass
o's class is classic.CClass

Nothing surprising here -- this is exactly what you'd expect.

Now, let's look at the annotation-style equivalent.

annot/AClassAspect.java
=======================
package annot;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.DeclareParents;

import x.X;

@Aspect
public class AClassAspect {
   public interface AClassIfc extends Cloneable {
      void callX();
   }

   public static class AClassImpl implements AClassIfc {
      public void callX() {
         X.x(this);
      }
      public Object clone() throws CloneNotSupportedException {
         try { return this.getClass().newInstance(); } catch (Exception e) {
throw new CloneNotSupportedException(e.toString()); }
      }
   }

   @DeclareParents(value="annot.AClass",defaultImpl=AClassIfc.class)
   private AClassIfc implementedInterface;
}

AClass.java
===========
package annot;

public class AClass {
   public static void main(String[] args) throws Exception {
      final AClass a = new AClass();
      System.out.println("Cloned object's class is
"+a.clone().getClass().getName());
      ((AClassAspect.AClassIfc) a).callX();
   }
}

Running this gives:
Cloned object's class is annot.AClass
Exception in thread "main" java.lang.InstantiationError:
annot.AClassAspect$AClassIfc
	at annot.AClass.callX(AClass.java:1)
	at annot.AClass.main(AClass.java:7)

I have to admit being surprised by both results -- the first simply did not meet
my expectations, as I thought I'd had "this" figured out.  The second is not
supposed to fail, but should've (from what I'm seeing in my anemic demo)
printed:
o's class is AClassAspect$AClassImpl

Interestingly, if I reorder the methods (the clone method is now first):
   public static class AClassImpl implements AClassIfc {
      public Object clone() throws CloneNotSupportedException {
         try { return this.getClass().newInstance(); } catch (Exception e) {
throw new CloneNotSupportedException(e.toString()); }
      }
      public void callX() {
         X.x(this);
      }
   }

I get the following result:
Cloned object's class is annot.AClassException in thread "main"
java.lang.InstantiationError: annot.AClassAspect$AClassIfc
	at annot.AClass.callX(AClass.java:1)
	at annot.AClass.main(AClass.java:7)

Something's going on...  Meanwhile, if I comment out the cloning stuff entirely
(in the interface and the impl), I still can't "callX".  Now, I'm curious why
I'm not getting this failure in my anemic demo...

I can file a bug on the traceback.  Assuming you trust me that my anemic
equivalent of callX passes this and not the target (and assuming I can continue
to avoid the issue this example has), how can I get the true target to pass to
callX?


Back to the top