ソースを参照

declareMixin

tags/pre268419
aclement 15年前
コミット
fccbab59a2
1個のファイルの変更185行の追加9行の削除
  1. 185
    9
      docs/adk15ProgGuideDB/ataspectj.xml

+ 185
- 9
docs/adk15ProgGuideDB/ataspectj.xml ファイルの表示

@@ -648,17 +648,37 @@
<title>Inter-type Declarations</title>

<para>
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.
Inter-type declarations are challenging to support using an annotation style. For code style aspects,
compiled with the ajc compiler, the entire type system can be made aware of inter-type declarations (new
supertypes, new methods, new fields) and the completeness and correctness of it can be guaranteed.
Achieving this with an annotation style is hard because the source code may simply be compiled with javac
where the type system cannot be influenced and what is compiled must be 'pure java'.
</para>
<para>
AspectJ 1.5.0 introduced @DeclareParents, an attempt to offer something like that which is achievable with
code style declare parents and the other intertype declarations (fields, methods, constructors). However,
it has proved too challenging to get close to the expressiveness and capabilities of code style in this area
and effectively @DeclareParents is offering a mixin strategy. The definition of mixin I am using here is that
some interface I is mixed into some target type T and that means all the methods from I are added to T and their
implementations are simple forwarding methods that call a delegate which that provides an implementation of I.
</para>
<para>
The next section here talks about @DeclareParents and what is possible, but moving forward, starting with
AspectJ 1.6.4, we are offering @DeclareMixin - an improved approach to defining a mixin and the choice of a different
name will hopefully alleviate some of the confusion about why @DeclareParents just doesn't offer the same
semantics as the code style variant. Offering @DeclareMixin also gives code style developers a new tool for a simple
mixin whereas previously they would have avoided @DeclareParents thinking what it could do was already achievable with
code style syntax.
</para>
<para>
In future releases the @DeclareParents support may be deprecated if it cannot be made more similar to code style.
</para>


<sect2 id="atDeclareParents" xreflabel="atDeclareParents">
<title>@DeclareParents</title>

<para>
Consider the following aspect:
</para>
@@ -798,6 +818,162 @@
If the interface defines one or more operations, and these are not implemented by
the target type, an error will be issued during weaving.
</para>
</sect2>
<sect2 id="atDeclareMixin" xreflabel="atDeclareMixin">
<title>@DeclareMixin</title>
<para>
Consider the following aspect:
</para>

<programlisting><![CDATA[
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());
}
}
]]></programlisting>

<para>
This declares an interface <literal>Moody</literal>, 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 <literal>getMoody</literal>, the type of <literal>this</literal> is <literal>Moody</literal>
(the target type of the inter-type declaration).
</para>

<para>Using the annotation style this aspect can be written:
</para>

<programlisting><![CDATA[
@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 DeclareMixin annotation is attached to a factory method that can return instances of the delegate
// which offers an implementation of the mixin interface. The interface that is mixed in is the
// return type of the method.
@DeclareMixin("org.xyz..*")
public static Moody createMoodyImplementation() {
return new MoodyImpl();
}

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

<para>
Basically, the <literal>@DeclareMixin</literal> annotation is attached to a factory method. The
factory method specifies the interface to mixin as its return type, and calling the method should
create an instance of a delegate that implements the interface. This is the interface which will
be delegated to from any target matching the specified type pattern.
</para>
<para>
Exploiting this syntax requires the user to obey the rules of pure Java. So references to any
targeted type as if it were affected by the Mixin must be made through a cast, like this:
</para>
<programlisting><![CDATA[
// 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();
...
}
}
]]></programlisting>

<para>
Sometimes the delegate instance may want to perform differently depending upon the type/instance for
which it is behaving as a delegate. To support this it is possible for the factory method to specify a
parameter. If it does, then when the factory method is called the parameter will be the object instance for
which a delegate should be created:
</para>
<programlisting><![CDATA[
@Aspect
public class Foo {
@DeclareMixin("org.xyz..*")
public static SomeInterface createDelegate(Object instance) {
return new SomeImplementation(instance);
}
}
]]></programlisting>
<para>
It is also possible to make the factory method non-static - and in this case it can then exploit
the local state in the surrounding aspect instance, but this is only supported for singleton aspects:
</para>
<programlisting><![CDATA[
@Aspect
public class Foo {
public int maxLimit=35;
@DeclareMixin("org.xyz..*")
public SomeInterface createDelegate(Object instance) {
return new SomeImplementation(instance,maxLimit);
}
}
]]></programlisting>
<para>
Although the interface type is usually determined purely from the return type of the factory method, it can
be specified in the annotation if necessary. In this example the return type of the method extends multiple
other interfaces and only a couple of them (I and J) should be mixed into any matching targets:
</para>
<programlisting><![CDATA[
// interfaces is an array of interface classes that should be mixed in
@DeclareMixin(value="org.xyz..*",interfaces={I.class,J.class})
public static InterfaceExtendingLotsOfInterfaces createMoodyImplementation() {
return new MoodyImpl();
}
]]></programlisting>
<para>
There are clearly similarities between <literal>@DeclareMixin</literal> and <literal>@DeclareParents</literal> but
<literal>@DeclareMixin</literal> is not pretending to offer more than a simple mixin strategy. The flexibility in
being able to provide the factory method instead of requiring a no-arg constructor for the implementation also
enables delegate instances to make decisions based upon the type for which they are the delegate.
</para>
<para>
Any annotations defined on the interface methods are also put upon the delegate forwarding methods created in the
matched target type.
</para>
</sect2>

</sect1>


読み込み中…
キャンセル
保存