Inter-type declarations

Aspects can declare members (fields, methods, and constructors) that are owned by other types. These are called inter-type members. Aspects can also declare that other types implement new interfaces or extend a new class. Here are examples of some such inter-type declarations:

This declares that each Server has a boolean field named disabled, initialized to false:

  private boolean Server.disabled = false;
It is declared private, which means that it is private to the aspect: only code in the aspect can see the field. And even if Server has another private field named disabled (declared in Server or in another aspect) there won't be a name collision, since no reference to disabled will be ambiguous.

This declares that each Point has an int method named getX with no arguments that returns whatever this.x is:

  public int Point.getX() { return this.x; }
Inside the body, this is the Point object currently executing. Because the method is publically declared any code can call it, but if there is some other Point.getX() declared there will be a compile-time conflict.

This publically declares a two-argument constructor for Point:

  public Point.new(int x, int y) { this.x = x; this.y = y; }

This publicly declares that each Point has an int field named x, initialized to zero:

  public int Point.x = 0;
Because this is publically declared, it is an error if Point already has a field named x (defined by Point or by another aspect).

This declares that the Point class implements the Comparable interface:

  declare parents: Point implements Comparable;
Of course, this will be an error unless Point defines the methods required by Comparable.

This declares that the Point class extends the GeometricObject class.

  declare parents: Point extends GeometricObject;

An aspect can have several inter-type declarations. For example, the following declarations

  public String Point.name;
  public void Point.setName(String name) { this.name = name; }
publicly declare that Point has both a String field name and a void method setName(String) (which refers to the name field declared by the aspect).

An inter-type member can only have one target type, but often you may wish to declare the same member on more than one type. This can be done by using an inter-type member in combination with a private interface:

  aspect A {
    private interface HasName {}
    declare parents: (Point || Line || Square) implements HasName;

    private String HasName.name;
    public  String HasName.getName()  { return name; }
  }
This declares a marker interface HasName, and also declares that any type that is either Point, Line, or Square implements that interface. It also privately declares that all HasName object have a String field called name, and publically declares that all HasName objects have a String method getName() (which refers to the privately declared name field).

As you can see from the above example, an aspect can declare that interfaces have fields and methods, even non-constant fields and methods with bodies.

Inter-type Scope

AspectJ allows private and package-protected (default) inter-type declarations in addition to public inter-type declarations. Private means private in relation to the aspect, not necessarily the target type. So, if an aspect makes a private inter-type declaration of a field

  private int Foo.x;
Then code in the aspect can refer to Foo's x field, but nobody else can. Similarly, if an aspect makes a package-protected introduction,

  int Foo.x;

then everything in the aspect's package (which may or may not be Foo's package) can access x.

Example: PointAssertions

The example below consists of one class and one aspect. The aspect privately declares the assertion methods of Point, assertX and assertY. It also guards calls to setX and setY with calls to these assertion methods. The assertion methods are declared privately because other parts of the program (including the code in Point) have no business accessing the assert methods. Only the code inside of the aspect can call those methods.

  class Point  {
      int x, y;

      public void setX(int x) { this.x = x; }
      public void setY(int y) { this.y = y; }

      public static void main(String[] args) {
          Point p = new Point();
          p.setX(3); p.setY(333);
      }
  }

  aspect PointAssertions {

      private boolean Point.assertX(int x) {
          return (x <= 100 && x >= 0);
      }
      private boolean Point.assertY(int y) {
          return (y <= 100 && y >= 0);
      }

      before(Point p, int x): target(p) && args(x) && call(void setX(int)) {
          if (!p.assertX(x)) {
              System.out.println("Illegal value for x"); return;
          }
      }
      before(Point p, int y): target(p) && args(y) && call(void setY(int)) {
          if (!p.assertY(y)) {
              System.out.println("Illegal value for y"); return;
          }
      }
  }