Introduction

Introduction declarations add whole new elements in the given types, and so change the type hierarchy. Here are examples of introduction declarations:

  private boolean Server.disabled = false;

This privately introduces a field named disabled in Server and initializes it to false. Because it is declared private, only code defined in the aspect can access the field.

  public int Point.getX() { return x; }

This publicly introduces a method named getX in Point; the method returns an int, it has no arguments, and its body is return x. Because it is defined publically, any code can call it.

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

This publicly introduces a constructor in Point; the constructor has two arguments of type int, and its body is this.x = x; this.y = y;

  public int Point.x = 0;

This publicly introduces a field named x of type int in Point; the field is initialized to 0.

  declare parents: Point implements Comparable;

This declares that the Point class now implements the Comparable interface. Of course, this will be an error unless Point defines the methods of Comparable.

  declare parents: Point extends GeometricObject;

This declares that the Point class now extends the GeometricObject class.

An aspect can introduce several elements in at the same time. For example, the following declaration

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

publicly introduces both a field and a method into class Point. Note that the identifier "name" in the body of the method is bound to the "name" field in Point, even if the aspect defined another field called "name".

One declaration can introduce several elements in several classes as well. For example,

  public String (Point || Line || Square).getName()  { return name; }

publicly introduces three methods, one in Point, another in Line and another in Square. The three methods have the same name (getName), no parameters, return a String, and have the same body (return name;). The purpose of introducing several elements in one single declaration is that their bodies are the same. The introduction is an error if any of Point, Line, or Square do not have a "name" field.

An aspect can introduce fields and methods (even with bodies) onto interfaces as well as classes.

Introduction Scope

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

  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 not be Foo's package) can access x.

Example: PointAssertions

The example below consists of one class and one aspect. The aspect introduces all implementation that is related with assertions of the class. It privately introduces two methods in the class Point, namely assertX and assertY. It also advises the two set methods of Point with before declarations that assert the validity of the given values. The introductions are made privately because other parts of the program 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;
          }
      }
  }