Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [aspectj-users] re: Possible?

David's suggestion is one possible idiom for handling this problem (which is commonly encountered with mock objects). The biggest drawback is if C relies on inherited behavior and B changes it (see below for more on that), then the work-arounds are klugey. Here are two other approaches:

1) "lobotomize": the original object. This is a new idea (that's probably worth a short paper) that generalizes an ad hoc approach people often use. You could create a subclass of the original class, but use highly polymorphic around advice to delegate all the operations.

E.g.,

class L extends B {
  L(C c) { this.c = c; }
  C getC() { return c; }
}

aspect MockB {
  B around(String string) : call(B.new(String)) {
    return new L(new C(String));
  }

  Object around(L l) : call(* *(..)) && target(l) {
    Method m = Class.getMethod(...); // look up the Method from thisJoinPoint.getSignature()
    // this is trickier if you are invoking non-public methods too: then you need to use getDeclaredMethod and climb the inheritance hierarchy
    return m.invoke(l.getC(), thisJoinPoint.getArgs());
  }
}

2) refactor to use a factory method to create the object which uses a defined interface. Then use around advice on the factory

Re: David's proposal suppose we had:

class D defining foo, B overriding foo, but C not (just inheriting it). Then calling c.foo should just execute d.foo, but with the declare parents approach, it would call the overriding b.foo. So your aspect would need to define 

void C.foo() { /* inline the body of d.foo(); */ }

Likewise if C overrode foo, and it called super.foo(), then overriding advice in the aspect would need to inline the body of d.foo() (or delegate to a helper method) to avoid executing b.foo().

Ron

Ron Bodkin
Chief Technology Officer
New Aspects of Security
m: (415) 509-2895

> ------------Original Message-------------
> From: David Vollbracht <alt@xxxxxxxxxxx>
> To: aspectj-users@xxxxxxxxxxx
> Date: Tue, Jun-17-2003 12:45 PM
> Subject: Re: [aspectj-users] re: Possible?
> 
> I think this does effective what you want, but to make this work
> you have to make C extend B (declared in the aspect) so it can be
> used as that type. Since they have the same public interface that
> shouldn't cause a problem, but you do have to add a no-arg constructor
> to B (again, declared in the aspect) since C's constructor knows nothing
> about B. Here a modified version of your sample code that does something
> close to what you want, I think.
> 
> public class A
> {
>  	private B m_b;
>  	
>  	public void method()
>  	{
>  		m_b = new B( "Test" );
>  		m_b.method();
>  	}
> 
>    public static void main( String[] args )
>    {
>       A a = new A();
>       a.method();
>    }
> }
> 
> class B extends D
> {
>    public B(String string)
>    {
>    }
>    
>    public void method()
>    {
>       System.out.println( "In B" );
>    }
> }
> 
> class C extends D
> {
>    public C(String string)
>    {
>    }
>    
>    public void method()
>    {
>       System.out.println( "In C" );
>    }
> }
> 
> class D
> {
> }
> 
> aspect BToC
> {
>    declare parents: C extends B;
> 
>    /**
>     * No-arg constructor for class B so Class C doesn't
>     * need to be changed
>     */
>    public B.new()
>    {
>       this( "Dummy String" );
>    }
> 
>    pointcut createB( String string ) :
>       call( B.new( String ) ) && args( string );
> 
>    B around( String string ) : createB( string )
>    {
>       return new C( string );
>    }
> }
> 
> When you run class A it does indeed print "In C".  Is this sufficient to
> answer your question?
> 
> David Vollbracht
> 
> On Tue, 17 Jun 2003 13:12:07 -0500
> "Anagnost, Ted (MED, GEMS-IT)" <Theodore.Anagnost@xxxxxxxxxx> wrote:
> 
> > Sorry if this is a repeat of my previous post:
> > 
> 
> -- original code example removed --
> 
> > > 
> > > Is it possible to change A so that when it tries to do this:
> > > 
> > > 		m_b = new B( "Test" );
> > > 		m_b.method();		
> > > 		
> > > it actually effectively does this:
> > > 
> > > 		m_b = new C( "Test" );
> > > 		m_b.method(); // calls C's method()		
> > > 	
> > > In other words can I used AspectJ to substitute another class C
> > > for class B (as long as it has the same inheritance model and public 
> > > interface) without changing the original source code?
> > > 
> > > 
> > > If the above is impossible, a related question is:
> > > 
> > > Can I create an aspect such that if there is a call to a method, that
> > > method call 
> > > is redirected to another object (that has a method of the same
> > > signature) instead?
> > > 
> > > And then when that other object's method call is finished, the
> > > original object's 
> > > method's code is bypassed altogether?
> > > 
> > > Thanks,
> > > 
> > > Ted
> > _______________________________________________
> > aspectj-users mailing list
> > aspectj-users@xxxxxxxxxxx
> > http://dev.eclipse.org/mailman/listinfo/aspectj-users
> _______________________________________________
> aspectj-users mailing list
> aspectj-users@xxxxxxxxxxx
> http://dev.eclipse.org/mailman/listinfo/aspectj-users
> 


Back to the top