Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [aspectj-dev] perthis and pertarget examples

Ciao Cristiano,
Aspects are classes, they can contain normal methods and normal fields,
and as any class they are instantiated. Normally, they are instantiated
as singletons, meaning that in the same JVM (formally, in the same
ClassLoader) there is only one active instance of an aspect. With
perthis, pertarget, percflow .. you change this behaviour. Basically,
when a before advice is in place :

public class Person {
  private String name;

  public void setName(String name) {
    this.name = name;
  }
}

public aspect CheckNameInPerson {
   before(String s) : execution(* Person.setName(s)) {
     if (s == null || s.length() == 0) throw new
RuntimeException("Cannot set a null name");
   }
}

AspectJ modifies the setName in the following way (I'll use humanized
language) :

public void setName(String name) {
  CheckNameInPerson checker = CheckNameInPerson.getInstance();
  checker.beforeSetName(name);
  this.name = name;
}

Actually, the code is a bit different, but that's the idea.

Now suppose we want to make another aspect, that sends an email with
changes executed on a Person bean. Obviously, I don't want a single
email for every call to a setter, instead I want to compose the text of
the email and send it later (for example when a certain method is
called, or when a certain amount of time is expired). To do this, I must
have the email "open" and available across more than one advices, and
most importantly I must have more than one mail, one per-person. Here
the perthis comes into play :

public aspect NotifyPersonOfChanges perthis(setter()) {
  
    private String mailtext = "There has been some changes:\n";

    pointcut setter() : execution(* Person.set*(..));

    after() returning : setter() {
       mailtext += "The field .... has changed with ... ";
    }
}

In this case, se same setter method will be enhanced differently from
AspectJ (again, using humanized language) :

public class Person {
  private NotifyPersonOfChanges notifier = new NotifyPersonOfChanges(this);

  public void setName(String name) {
    this.name = name;
    notifier.afterSetter();
   }
}

Again, this is not really HOW it happens, but is very close to WHAT
happens, written in a more java familiar way.

As you can see, a new instance of NotifyPersonOfChanges is created for
each Person, so the private String mailtext will be one for each person,
and no person will receive an email with changes regarding another person.

This is done thanks to the perthis directive, it simply takes the "this"
of the given pointcut (a Person instance in our case), creates a new
instance of the aspect, and binds it to the "this" so that it will not
be recreated the next time and that no two instances of "this" will
share the same instance of the aspect.

Pertarget works in a very similar way, except that it takes the "target"
instead of the "this" of the specified pointcut, so it has meaning when
used together with the call() pointcut definition. If for example we
want to trace the calls to the write method or an OutputStream, we
cannot write :

public aspect StreamTracer perthis(streamwrite()) {
  pointcut streamwrite() : execution(* OutputStream+.write(..));

Since AspectJ cannot advice classes in the JRE, this pointcut will not
be triggered when writing in a FileOutputStream, for example. Instead we
can write :

public aspect StreamTracer pertarget(streamwrite()) {
  pointcut streamwrite() : call(* OutputStream+.write(..));

Since our program is accessible by AspectJ, it will find all calls in
our code where we write to a stream, and instantiate one instance of the
StreamTracer aspect for each OutputStream. A simple example of such an
aspect is :

public aspect StreamTracer pertarget(streamwrite()) {
  private String logentry = "Stream writes:\n";
 
  pointcut streamwrite() : call(* OutputStream+.write(..));
  pointcut streamclose() :  call(* OutputStream+.close());

  after() : streamwrite() {
    logentry += System.currentTimeMillis() + " : written a block";
  }

  after() : streamclose() {
    LogSystem.logDebug(logentry);
  }
}

Hope it helps (and everything is correct :D ),
Simone


Cristiano de Favari wrote:
> Hi all,
>
> Does Anybody have some clear examples of perthis and pertarget
> constructions ? AspectJ in action and even sites I have seen are not
> so clear. I have worked in some code as well, but It's not clear for
> me yet analysing the results.
>
> Thank you all in advance.
> ------------------------------------------------------------------------
>
> _______________________________________________
> aspectj-dev mailing list
> aspectj-dev@xxxxxxxxxxx
> https://dev.eclipse.org/mailman/listinfo/aspectj-dev
>   


-- 
Simone Gianni
http://www.simonegianni.it/
CEO Semeru s.r.l.
Apache Committer



Back to the top