Hi all,

I've used a common ITD pattern for years now to introduce interface
implementation(s) into existing classes when I have well-encapsulated,
orthogonal state & behavior that I want to introduce.  Here's a simple
example (hand-written, but gives you the gist):  suppose several of my
domain entities need to have a string property "name".

First, define an interface that describes the behavior:

package org.example.traits;

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

Next, define an annotation that can be used to drive introduction:

package org.example.traits;

@Target(TYPE)
@Retention(RUNTIME)
public @interface Expresses {
    Class[] value();
}

Next, define an aspect that provides an implementation of the behavior:

package org.example.traits;

public privileged aspect NameableAspect {

public interface I extends Nameable {
 }

declare parents : (@Expresses(..,Nameable.class,..) *) implements I;

private String I.name;

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

 public String I.getName() {
 return name;
}
}

Last, annotate a class that needs to receive the ITD:

package org.example.domain;

// imports...

@Expresses(Nameable.class)
public class Person {
}

After considering JDK8 <http://openjdk.java.net/projects/lambda/>'s default
methods<http://cr.openjdk.java.net/~briangoetz/lambda/Defender%20Methods%20v4.pdf>feature
and comparing it to Scala's
traits <http://www.scala-lang.org/node/126> and
mixins<http://www.scala-lang.org/node/117>,
I realized that AspectJ, with a little syntax sugar, could have the same
features as Scala.  The above example could be rewritten as the following,
depending on how many new keywords were introduced.

First, define the trait's state & full or partial behavior using a proposed
new keyword "trait":

package org.example.traits;

trait Nameable {

    String name;

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

    String getName() {
        return name;
    }
}

Here is what ajc would do with the trait:

   - produce a public interface with the same name as the trait with the
   trait's methods, and
   - define an aspect that
      - introduces the trait's fields and the implementations of the
      trait's methods into the produced interface, and
      - uses @Expresses to drive a declare parents statement to mix in the
      implementation into classes that are annotated with @Expresses.

With this syntax, a user could simply declare that a class needs to express
the trait:

package org.example.domain;

import org.example.traits.Nameable; // interface generated from trait

@Expresses(Nameable.class)
public class Person {

    public Person(String name) {
        setName(name);
    }

    // ...
}

In summary, this proposal is just syntax sugar over features that are
already present in AspectJ for quite a while.  It would be nice, as part of
this enhancement, if
https://bugs.eclipse.org/bugs/show_bug.cgi?id=288282could be resolved
so that the ajc-generated, mangled accessors & mutators
aren't present in the mixed in class (because
https://bugs.eclipse.org/bugs/show_bug.cgi?id=73507 is now fixed).

WDYT?

-matthew

-- 
mailto:matt...@matthewadams.me <matt...@matthewadams.me>
skype:matthewadams12
googletalk:matt...@matthewadams.me
http://matthewadams.me
http://www.linkedin.com/in/matthewadams
_______________________________________________
aspectj-users mailing list
aspectj-users@eclipse.org
https://dev.eclipse.org/mailman/listinfo/aspectj-users

Reply via email to