Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [aspectj-users] Around, Constructors and ClassCastException

Hi John -

It's as you suspected, a Java requirement.

The return type of the constructor-call join point is the
type of the object being constructed.  You can only replace
it with an instance of that class or a subclass.

If, on the other hand, you had a factory method that
returned Animal, then you could replace the result with any
Animal.  Everything would work  (unless some client of 
the factory method tried to downcast the result to the 
wrong type).

This is just basic type-safety in Java.  In all cases but
the one you propose, AspectJ enforces this at compile-time.
However, returning "Object" from around advice is a way
to write around advice that advises join points with 
different return types.  It's then the responsibility of
the
programmer to ensure the type returned is correct.  To
get the return type of the actual join point at runtime,
use
  ((ConstructorSignature) // or MethodSignature   
    thisJoinPointStaticPart.getSignature())
    .getReturnType()

(btw, this strikes me as a bug in the API - I'd think
getReturnType() should be in the CodeSignature interface)

You should only declare around advice to return Object when
the join point returns Object or when there is no other
common subtype of the return types of the join points.
So if your pointcut was

  call(SmallDog.new(..))

you would declare that the around advice
returns SmallDog, and the compiler would signal an error
if you try to return BigDog.  Then at least you would
realize it is not possible without having to run tests.

I did confirm that this is not stated in the AspectJ
Programming Guide, so I'll update that.

Thanks for the question, and sorry the topic wasn't covered
in the documentation.

Wes

On Thu, 23 Mar 2006 11:00:54 -0500
 "John Adams" <jadams3@xxxxxxxxxx> wrote:
> 
> Hello,
> 
> I've looked a fair bit now for the answer to this
> question in the
> archives and the manuals, but I haven't seen anything
> yet.  I am trying
> to see whether I can replace an object at runtime with a
> different
> implementation.  I have had some success replacing
> subclasses, but I
> haven't been able to replace it with another
> implementation.  I suspect
> a byte code limitation, but I thought I'd check here.
> 
> Essentially I'm trying to advise the following code ...
> 
> Animal anAnimal = new SmallDog();
> 
> Where SmallDog implements Animal, and Animal is an
> interface that looks
> like ...
> 
> public interface Animal {
> 	void speak();
> }
> 
> I was trying to replace the SmallDog() with a BigDog()
> with an aspect.
> I can do it if BigDog extends SmallDog, but being an
> Animal is
> insufficient for the aspect to work, I end up throwing a
> ClassCastException. 
> 
> public aspect ConstructorReplaceCall {
>        public pointcut init(): call(test.*.new(..));
> 
>        Object around(): init() {
>           if (someTestLogicIsTrue) {
>         	  return new BigDog(); // ok if BigDog extends
> SmallDog,
> not ok if BigDog only implements animal
>           } else{
>         	  return proceed();
>           }
>       }
> }
> 
> Am I missing something or is this a fundamental
> 'limitation' of the Java
> bytecode that is generated ?  (where limitation could
> mean you're insane
> to do otherwise :) ) 
> 
> Thanks in advance,
> John.
> 
> 



Back to the top