[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[aspectj-dev] language: declare advisedby

In some cases, I'd like to ensure that aspects do not
affect a particular type or set of join points.  It is
not that an aspect must be disabled, but that some bunch
of code must stay as-is.  We might like to say

- the non-public interface of this set of classes
is off-limits

- nothing should affect this aspect

- we can't change the interfaces or fields of a set
of classes deployed in the wild

The syntax might be something like:

  declare unadvised: {pointcut} {: "message"};
  declare unaffected: {type-pattern} {: "message"};

(where pointcut is staticly-determinable)?

The semantics:

  declare unadvised: pc() : "message";

specifies that if there is any advice on the join points picked
out by pc(), the compiler will emit an error containing "message".

declare unadvised: pc();

specifies that no advice will be implemented on the join points
picked out by pc().  No message is emitted.  For developers who
want a message in any case, we can support an XLint message
(off by default) detecting that advice has been suppressed.

declare unaffected: Type+ : "no members on Thread";

specifies that no inter-type declarations are implemented on
types identified by Type+.  Like declare-unadvised, this emits
an error if a messages is included, and is silent otherwise,
unless the corresponding XLint message is enabled.

Semantic variants and caveats:

- declare-unaffected could also prohibit any join points
implemented within Type+, but since it is easy to say

   declare unadvised : within(Type+)

it seems better to maintain separate semantics.

- If an aspect is declared to dominate the aspect containing
the declare-unadvised/unaffected statement, then the compiler
can permit the caveat by implementing the advise and inter-type
declarations of that aspect.

- To be more general, we could use friends:

  declared advisedby {typepattern} : {pointcut} {: "message"};


  declared advisedby com.company.as..* : within(com.company..*);

The "unadvised" case is just

  declared advisedby !Object+ : {pointcut} {: "message"};

This permits us to have controlled aspect interactions,
rather than just prohibiting them:

  declared advisedby (com.company.lib.sync..*)+ :


The implementation for advice is to have a munger that aborts
further munging.  I'm not sure about the implementation
for inter-type declarations.

Drawbacks and alternatives:

This scatters the definition of crosscutting by permitting other
aspects to disable advice, possibly without warning.  This effect
is mitigated by notice from the XLint message, and could be
supported in the IDE by listing advice disabled by a given
declare-unadvised statement (and perhaps using syntax-highlighting
to grey out disabled advice and declarations?).


This can implement some broad policies about the use of aspects.
This can help people do incremental adoption, particularly to
adopt binary aspects, and ensure that some code is untouched.
It might also help in debugging aspects themselves.

This provides some protection against the variability introduced
by using AOP/AspectJ.  More than just respecting Java's
type-safety and visibility rules, AspectJ can do more to give
developers a way to control aspect interference and interaction.