Inter-type Declarations
Prev | Chapter 9. An Annotation Based Development Style | Next

## Inter-type Declarations

Inter-type declarations are challenging to support using an annotation style. It's very important to preserve the same semantics between the code style and the annotation style. We also want to support compilation of a large set of @AspectJ applications using a standard Java 5 compiler. For these reasons, the 1.5.0 release of AspectJ 5 only supports inter-type declarations backed by interfaces when using the annotation style - which means it is not possible to introduce constructors or fields, as it would not be not possible to call those unless already woven and available on a binary form.

Consider the following aspect:

         public aspect MoodIndicator {

            public interface Moody {};

            private Mood Moody.mood = Mood.HAPPY;

            public Mood Moody.getMood() {
              return mood;
            }

            declare parents : org.xyz..* implements Moody;

            before(Moody m) : execution(* *.*(..)) && this(m) {
               System.out.println("I'm feeling " + m.getMood());
            }
         }

This declares an interface `Moody` , and then makes two inter-type declarations on the interface - a field that is private to the aspect, and a method that returns the mood. Within the body of the inter-type declared method `getMoody` , the type of `this` is `Moody` (the target type of the inter-type declaration).

Using the annotation style this aspect can be written:

         @Aspect
         public class MoodIndicator {

            // this interface can be outside of the aspect
            public interface Moody {
              Mood getMood();
            };

            // this implementation can be outside of the aspect
            public static class MoodyImpl implements Moody {
               private Mood mood = Mood.HAPPY;

               public Mood getMood() {
                 return mood;
               }
            }

            // the field type must be the introduced interface. It can't be a class.
            @DeclareParents(value="org.xzy..*",defaultImpl=MoodyImpl.class)
            private Moody implementedInterface;

            @Before("execution(* *.*(..)) && this(m)")
            void feelingMoody(Moody m) {
               System.out.println("I'm feeling " + m.getMood());
            }
         }

This is very similar to the mixin mechanism supported by AspectWerkz. The effect of the `@DeclareParents` annotation is equivalent to a declare parents statement that all types matching the type pattern implement the given interface (in this case Moody). Each method declared in the interface is treated as an inter-type declaration. Note how this scheme operates within the constraints of Java type checking and ensures that `this` has access to the exact same set of members as in the code style example.

Note that it is illegal to use the @DeclareParents annotation on an aspect' field of a non-interface type. The interface type is the inter-type declaration contract that dictates which methods are declared on the target type.

         // this type will be affected by the inter-type declaration as the type pattern matches
         package org.xyz;
         public class MoodTest {

            public void test() {
                // see here the cast to the introduced interface (required)
                Mood mood = ((Moody)this).getMood();
                ...
            }
        }

The `@DeclareParents` annotation can also be used without specifying a `defaultImpl` value (for example, `@DeclareParents("org.xyz..*")`). This is equivalent to a `declare parents ... implements` clause, and does not make any inter-type declarations for default implementation of the interface methods.

Consider the following aspect:

         public aspect SerializableMarker {

            declare parents : org.xyz..* implements Serializable;
         }

Using the annotation style this aspect can be written:

         @Aspect
         public class SerializableMarker {

            @DeclareParents("org.xyz..*")
            Serializable implementedInterface;
         }

If the interface defines one or more operations, and these are not implemented by the target type, an error will be issued during weaving.

Prev | Home | Next
Pointcuts and Advice | Up | Declare statements