Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [aspectj-users] Advising all methods that modify transientfields

> I would actually like to capture all methods in which
> non-transient
> fields are modified for a given storage class. 

There isn't a way in AspectJ to pick out a join point
based on whether other join points might occur within
the scope of its execution, even if that's determinable.
You can get the signature of the enclosing join point,
but you don't want to replace a field-set with a 
reflective call to the method containing it.  Even if
you avoid advice advising itself, there might be code
before or after the set in the method.

If you really want to do this, one solution is to 
convert "state changes" to setter methods in one 
of two ways.  (Neither way gives you the benefit of
grouping a set of state changes for persistence at
one point -- do you miss the C++ const specifier yet?
-- for AspectJ used to try to close over a whole 
series of messages, see the CricketCage project.)

First, if the developers could accept this, you could
have a policy of no field sets outside a setter {unless
during initialization}.  You could also enforce that there
would be no other side-effects in a setter.  Together these
make setter methods into (nothing other than) state changes
and you can identify and work with the state changes much
more easily. Group sets would have to be explicitly
coded as such.

Some enforcement sample code:

- warn (error) when setting fields outside a setter:
http://dev.eclipse.org/viewcvs/indextech.cgi/~checkout~/aspectj-home/sample-code.html#declares-inoculated-nonSetterWrites

- prohibit field writes by other instances
http://dev.eclipse.org/viewcvs/indextech.cgi/~checkout~/aspectj-home/sample-code.html#testing-inoculated-prohibitWritesByOthers

- prohibit field writes after construction
  (or outside a prevayler transaction?)
  http://dev.eclipse.org/viewcvs/indextech.cgi/~checkout~/aspectj-home/sample-code.html#testing-inoculated-prohibitWritesExceptWhenConstructing

Second, if you can't have that policy, then you can just
make it so using an aspect.  (Given lemons, make lemonade.)
The "setter" can be an inter-type declaration (have to
specify each) or a reflective implementation, which you
could combine with transaction handling.  

At runtime, the original join points

   call(Foo.setVar(..))
      set(Type Foo.var)

becomes these (ignoring all but the around advice):

   call(Foo.setVar(..))
      {set(Type Foo.var) --> replaced using around}
        call(void ???.setFooVar(Foo, Var)) <-- replacement
          execution(void ???.realsetFooVar(Foo, Var))
            set(Type Foo.var)

Either the call or the execution of any/all realset*
method/s can be advised by the transactional aspect
(or others targeting state changes).

A brief example:
------ Main.java

import org.aspectj.lang.JoinPoint;

public class Main {

    int i;
    String s;
	public static void main(String[] args) {
	   new Main().run();
    }
    Main() {
        i = 1;
        s = "me";
    }
    void run() {
        i++;
        s += "you";
    }
}

aspect GlobalSetter {
   // for non-static fields - adjust for static
   void around(Object targ, Object value):
        set(!transient * *.*) && target(targ)
        && args(value) && !within(GlobalSetter) {
        globalSet(targ, value, thisJoinPointStaticPart);
   }
   boolean doI;

   void globalSet(Object targ, Object value, 
                  JoinPoint.StaticPart jpsp) {           
        // real code would have a reflective set here
        doI = !doI;
        if (doI) {
            System.out.println("setting i to " + value);
            ((Main) targ).i = ((Integer) value).intValue();
        } else { 
            System.out.println("setting s to " + value);
            ((Main) targ).s = (String) value;
        }
   }
}
aspect HandleTransactions {

    declare precedence : HandleTransactions, GlobalSetter;
    
    void around(JoinPoint.StaticPart jpsp) : 
        execution(void GlobalSetter.globalSet(..,
                                  JoinPoint.StaticPart))
        && args(.., jpsp) {
        System.out.println("starting");
        //startTransaction();
        proceed(jpsp);
        System.out.println("  ending");
        //endTransaction();        
    }
}
------

Note that the global-set aspect is logically independent
from transactions, which is just one policy applied to
localizing sets.  For a related example and a reflective
implementation, see the sample code "use getter/setter
pattern to track dirtiness":

http://dev.eclipse.org/viewcvs/indextech.cgi/~checkout~/aspectj-home/sample-code.html#caching-dirty-reflectiveSetters

I personally am not a fan of using reflection here;
if I had a real application I'd probably try to 
generate the realsetters rather than using reflection,
or wait for some combination of metadata and static
analysis to help out.

Wes

On 03 Dec 2003 01:19:47 -0500
 Jason van Zyl <jvanzyl@xxxxxxxxx> wrote:
> On Mon, 2003-11-10 at 14:27, Frank Sauer wrote:
> > I think adding !transient to your set pointcut should
> do the trick.
> > E.g. set(!transient * *.*)
> 
> I would actually like to capture all methods in which
> non-transient
> fields are modified for a given storage class. I would
> like to use
> around advice so that may use the join point signature to
> execute the
> method via reflection within a prevayler transaction
> 
> I just tossed the stuff in CVS here to try and make it
> easier to see
> exactly what I'm trying to do:
> 
>
http://cvs.codehaus.org/viewcvs.cgi/outhaus/jvanzyl/aspects/src/main/org/codehaus/top/prevayler/?root=codehaus
> 
> I was hoping to generalize within AbstractPersistence.aj
> and then extend
> that to specify the particular storage class I'm dealing
> with.
> 
> 
> > Frank 
> > 
> > -----Original Message-----
> > From: aspectj-users-admin@xxxxxxxxxxx
> > [mailto:aspectj-users-admin@xxxxxxxxxxx] On Behalf Of
> Jason van Zyl
> > Sent: Sunday, November 09, 2003 5:35 PM
> > To: aspectj-users@xxxxxxxxxxx
> > Subject: Re: [aspectj-users] Advising all methods that
> modify
> > transientfields
> > 
> > 
> > On Sun, 2003-11-09 at 17:19, Jason van Zyl wrote:
> > > Howdy,
> > > 
> > > Is there a way to do this? I'm trying to write a
> little Aspect to use 
> > > with Prevayler for transparent object persistence.
> > 
> > Sorry about the typo, that is obviously non-transient
> fields ...
> -- 
> jvz.
> 
> Jason van Zyl
> jason@xxxxxxxxxxx
> http://tambora.zenplex.org
> 
> In short, man creates for himself a new religion of a
> rational
> and technical order to justify his work and to be
> justified in it.
>   
>   -- Jacques Ellul, The Technological Society
> 
> _______________________________________________
> aspectj-users mailing list
> aspectj-users@xxxxxxxxxxx
> http://dev.eclipse.org/mailman/listinfo/aspectj-users



Back to the top