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.
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
.
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; } } }