Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[aspectj-users] @DeclareMixin support

We have many (valid!) bugs raised against AspectJ complaining that @DeclareParents is not the same as code style declare parents.  That is basically because @DeclareParents is not doing the same thing as code style declare parents, it is just a mixin.  To call out this difference and recognize the mixin pattern as being a nice solution to some kinds of problem, there is some new annotation style syntax.  This may even be useful in code style aspects.

This is in the latest AspectJ dev builds and some of it is even in the AJDT 1.6.4 release candidate (although you will have to keep doing full builds if trying it out in AJDT - incremental is broken).  It is still subject to change whilst I bed it in.

The new syntax is called @DeclareMixin - it is for mixing in an interface and associate delegate implementation into some target type.  It is effectively what @DeclareParents does today, but a rather neater syntax and addresses some of the problems users have had with @DeclareParents.  I'll now show it in action then talk about some of the open questions that we are still working through - any input on any of this is appreciated.

Best to show by example:

interface Named {
  public String getName();
  public void setName(String name);
}

class NamedImpl {
  String name;
  public String getName() { return this.name; }
  public void setName(String name) { this.name = name; }
}

class SomeClass {
}

aspect X {
  @DeclareMixin("SomeC*")
  public static Named createImpl() {
    return new NamedImpl();
  }
}

Instances of SomeClass can then be treated as if they implement Named (the type pattern for which types get the mixin is expressed as the annotation value):

  ((Named)new SomeClass()).getName();

Effectively the interface Named has been mixed-in to SomeClass and that means forwarding methods have been created within SomeClass that forward to a delegate implementation of Named, called NamedImpl.  Instances of the delegate are created through calls to the factory method that has been annotated.

This is what @DeclareParents actually does today but the syntax is not so friendly and there is no control over the factory method - it demands a no-arg constructor in the named implementation.

The flexibility with @DeclareMixin is that I can specify that the factory method takes a parameter:

  @DeclareMixin("SomeC*")
  public static Named createImpl(Object o) {
    return new NamedImpl(o);
  }

and when the factory method is called, the parameter value will be the instance of the target class for which the delegate is to be created - *this addresses an open bug we have about how does the mixin instance access the object for which it is being mixed in*.

You may notice that the factory method is static here - but it does not have to be.  If non-static then it can use aspect instance state that is accessible - but this is currently only supported for singleton aspects.

So there you have the basics - there are more details in this hastily put together piece of doc: http://www.eclipse.org/aspectj/doc/released/adk15notebook/ataspectj-itds.html

Open questions I am working through right now:

1) Does it need a simplified form for just mixing in a marker interface (that has no methods).  Here it is attached to just a field - the mixin interface is MarkerInterface:

@DeclareMixin("SomeC")
public static MarkerInterface foo;

(this is very similar to @DeclareParents)

2) What happens with clashing methods that already exist in the target.  Is the mixin considered to be a 'default implementation' (similar to our ITDs), or should it override whatever exists in the target, or should it be configurable as sometimes you'd want one scenario, sometimes the other.  I don't know enough about how this is handled in other languages that already support mixin's - if someone does, please chip in on this question since it would be silly to waste time solving something that other languages already have.

3) How to cleanly sort out the existing @DeclareParents.  Current thoughts are to simply deprecate defaultImpl - leaving @DeclareParents to more closely resemble code style 'declare parents' which just modifies the parent hierarchy, it doesn't add methods into the target (that is done by ITDs).  If someone wants to use defaultImpl with @DeclareParents, they should use migrate to @DeclareMixin instead.

comments? Thanks to Ramnivas for helping me get the syntax this far.
Andy.

Back to the top