Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [aspectj-users] Dynamic type casting

Hi Wes & Ramnivas,

Sorry for the confusion.  I was somehow overlooked the problem. Now It is
working
for me. But I'm giving more details here what I was thinking...


I will try to explain my problem in more detail here:

I mentioned my code in 3 classes like
- MyAspect.java       is the AspectJ code for my aspect
- Class A & Class B  - are the classes on which the aspect is applied.

Here I am adding one more class which uses Class A & Class B

===========Client.java====================================

public static void main(String[] args) {
    Class A = (new A()).load(1);  // here I am getting instance of A with
identity '1'.
    .............
    .............
    Class B = (new B()).load(1);  // here I am getting instance of B with
identity '1'.
    .............
    .............
}
============================================================

- Please observe the following lines of code in MyAspect.java :
  Object returnValue = myapp.PersistenceHandler.load(className, args);
/*Here I get common Object, but the Object is 'className' type. */
   return returnValue;


   In my aspect I'm getting the correct class name from thisJoinPoint like A
or B.  And I am calling
   myapp.PersistenceHandler.load(className, args). Here I thought I would
have problem.

   Here I am giving more details about PersistenceHandler.load(className,
args)  method{
        This method returns java.lang.Object but its class is the passed
'className'.
        When I use this method in other java  class, I should type cast to
the respective class as I am getting
        java.lang.Object like this:
        A aObj = (A) myapp.PersistenceHandler.load("A", Object[] {new
Integer(1)});
                       ------
   }

   So here I thought "Client.java" will get ClassCastException when it call
A.load() & B.load()
   as my aspect was returning java.lang.Object.
   So I asked for some AspectJ construct to type cast the Object to the
respective class type.
   But AspectJ is doing it by default. There is no need to use extra
construct for that.


Thanks a lot for your responses.
Venkat


----- Original Message -----
From: "Wes Isberg" <wes@xxxxxxxxxxxxxx>
To: <aspectj-users@xxxxxxxxxxx>
Sent: Thursday, September 04, 2003 12:11 AM
Subject: Re: [aspectj-users] Dynamic type casting


> Hi Venkat, Ramnivas -
>
> Venkat brings up two issues:
>
> -- runtime class of "this" in method execution join points
>
> V. suggests the type of "this" for method execution is Object
> when it should be A or B.  That would be a bug, but I am
> unable to reproduce it.  Using a variant of the code below,
> I get "A" and "B", not "java.lang.Object", as the className.
> If you can write a test case that causes this, please submit
> it as a bug.
>
> -- implicit dynamic casts of around advice return values
>
> I think Venkat is concerned about getting ClassCastException
> from returning the wrong type at a particular join point.
> Ram is right that the sample code looks correct, but it's
> worth an explanation.
>
>  From the AspectJ programming guide:
>
>   If the return value of around advice is typed to Object,
>   then the result of proceed is converted to an object
>   representation, even if it is originally a primitive
>   value. And when the advice returns an Object value,
>   that value is converted back to whatever representation
>   it was originally.
>
> It is this "converting back" that might fail.
>
> This danger lurks whenever one uses around advice declared
> to return a supertype of the type the join point returns.
> AspectJ's implicit casts will cause runtime ClassCastException
> if the advice body returns the wrong subtype for a given
> join point.  There is no good way AspectJ can prevent this
> at compile time, so the question is how to detect/test it.
>
> When around advice changes the return value, I prefer to
> specify the type returned to enjoy the benefits of compile-time
> type safety.  When I specify the subtype, the compiler will
> signal an error if someone changes the pointcut to include
> join points returning a different type.
>
> Doing this might mean breaking out different pieces of around
> advice which delegate to a common implementation method,
> as well as separating out the pointcuts to enforce the subtypes.
> The pointcuts could be refactored into type-specific
> variants of a common pointcut.[1]
>
> E.g., the pointcuts
>
>    pointcut loaders () : execution(* load(..));
>    pointcut loadersOfB () : loaders() && execution(B *(..));
>    pointcut loadersOfA()  : loaders() && execution(A *(..));
>
> are used by the different advice, delegating to the factory:
>
>    A around() : loadersOfA() {
>       return (A) makeThings(A.class, thisJoinPoint.getArgs());
>    }
>    B around() : loadersOfB() {
>       return (B) makeThings(B.class, thisJoinPoint.getArgs());
>    }
>
> Separating out the common functionality into a method (here
> "makeThings(...)" can make it easier to test this method to
> ensure that it returns the correct subtypes.[2]
>
> The problem is still there, but the solution is more testable
> and less prone to accidentally upgrading the pointcut without
> upgrading the advice functionality.
>
> Wes
>
> [1] Yes, to avoid respecifying the kinded pointcut execution(..),
> it might be nice to have a staticly-determinable PCD
>
>      returns(Type)
>
> Perhaps this could even be used to identify subtypes, to
> make it possible to write declare errors for pointcuts
> that were modified to pick out join points returning new
> subtypes:
>
>     // join points declared to return a subtype of Type
>     returns(Type+) && !returns(Type)
>
> Then you could declare an error whenever someone updated
> a pointcut to include a join point declared to return a subtype
> of a given type that wasn't included in a list of approved
> (i.e., tested) subtypes.  This would be better than [2].
>
> [2] You still have to manually track what return types need
> to be covered by the method to keep the advice and method in
> sync, so you'll have to have comments or docs that when there
> are new advice clients of the delegate method, the test should
> be updated to cover the new types.
>
> If you really wanted to fix that problem, delegate not to
> the generic factory but to type-specific clients of the
> factory and declare a warning for any clients that are
> not known and tested.  This might add too much complexity
> for some, but might work well when the advice and factory
> method are in separate components.  E.g.,:
>
> aspect Factory {
>
>      // type-specific around advice
>      Point around() : call(Point.new(..)) {
>          return makePoint(thisJoinPoint.getArgs());
>      }
>      Line around() : call(Line.new(..)) {
>          return makeLine(thisJoinPoint.getArgs());
>      }
>
>      // type-specific factory for declare error below to track
>      Line makeLine(Object[] args) {
>          return (Line) makeThings(Line.class, args);
>      }
>      Point makePoint(Object[] args) {
>          return (Point) makeThings(Point.class, args);
>      }
>
>      // the factory itself
>      Object makeThings(Class clazz, Object [] args) {
>          ...
>      }
>
>      // track factory clients to avoid untested new clients
>      declare error : call(Object makeThings(Class, Object[]))
>          && !withincode(Line Factory.makeLine(Object[] args))
>          && !withincode(Point Factory.makePoint(Object[] args)) :
>          && !within(FactoryTest) :
>          "Untested factory client!  "
>          + "Update "
>          + FactoryTest.class.getName()
>          + ", and update declare error pointcut in "
>          + Factory.class.getName();
>
>      // could also put pointcut in test, but this creates a
>      // dependency of production code on test code:
>      // declare error : call(Object makeThings(Class, Object[]))
>      //    && !FactoryTest.testedFactoryClients() : "Untested ...
> }
>
>
> Ramnivas Laddad wrote:
> > Venkat,
> >
> > The question is not completely clear to me. But from what
> > I gather, your aspects and classes as shown here should
> > work just fine. When you return type "Object" from around
> > advice, AspectJ compiler will perform the necessary casting
> > (as well as wrapping and unwrapping, in case of primitive
> > types).
> >
> > This information is a part of a free sample chapter of
> > "AspectJ in Action" (chapter 3, section 3.2.7):
> > http://www.manning.com/laddad/
> >
> > Try it and let us know if it works.
> >
> > -Ramnivas
> >
> >
> > --- Venkat Dosapati <venkat@xxxxxxxxxxxxxxxxx> wrote:
> >
> >>Sorry, my previous mail was missing the question. Here are the full
> >>details with the question:
> >>
> >>Please see the question in the end.
> >>
> >>==============MyAspect.java====================
> >>public aspect MyAspect {
> >>
> >> Object around() : execution(* *.load(..)) {
> >>  Object receiver = thisJoinPoint.getThis();
> >>  String className = receiver.getClass().getName();
> >>  Object[] args = getArguments(thisJoinPoint);
> >>  System.out.println("Class:" + className + "::ARGS:" + args);
> >>
> >>  Object returnValue = myapp.PersistenceHandler.load(className,
> >>args); /*
> >>Here I get common Object, but the Object is 'className' type. */
> >>  return returnValue;
> >> }
> >>
> >> private Object[] getArguments(JoinPoint jp)
> >> {
> >>  Object[] argumentValues = jp.getArgs();
> >>  return argumentValues;
> >> }
> >>}
> >>===============================================
> >>
> >>
> >>================Class A=========================
> >>public class A {
> >>
> >>    public A load(int id) {
> >>        // no implementation
> >>        return null;
> >>    }
> >>}
> >>================================================
> >>
> >>
> >>================Class B=========================
> >>public class B {
> >>
> >>    public B load(int id) {
> >>        // no implementation
> >>        return null;
> >>    }
> >>}
> >>===============================================
> >>
> >>
> >>
> >>When I replace the load() method in 2 classes A & B with my aspect,
> >>the
> >>advice is returning the common Object. But the classes A & B should
> >>return
> >>their respective type object.
> >>
> >>how can I type caste the Object to its original class in my aspect
> >>like
> >>this:
> >>
> >>Object returnValue = myapp.PersistenceHandler.load(className, args);
> >>return (className) returnValue;  /* Here className is the variable
> >>for the
> >>class name */
> >>
> >>[I think it is not possible with JAVA. Is it possible with AspectJ?]
> >>
> >>
> >>Thanks in advance!
> >>Venkat
> >>
> >>
> >>
> >
> >
> >
> > __________________________________
> > Do you Yahoo!?
> > Yahoo! SiteBuilder - Free, easy-to-use web site design software
> > http://sitebuilder.yahoo.com
> > _______________________________________________
> > 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