Introductions

    Introductions

     

    Overview

    JBossAOP has the ability to force a Java class to implement an interface.  You can even specify a Mixin Class that will be instantiated and attached to an instance of that class.  So, if you force a Java class to implement an interface, it can delegate an introduced methods of that interface to the Mixin class instance.

     

    Making a non-serializable class Serializable

    Take a look at POJO.java.  You will see that it is non-serializable.  Then take a look jboss-aop.xml:

       <introduction class="POJO">
          <interfaces>
             java.io.Serializable
          </interfaces>
       </introduction>
    

     

    The first introduction declaration, introduces/forces POJO to implement Serializable.  When the aopc compiler is run, it will transform POJO to implement that interface.  If you used a decompiler to look at POJO.class, you would find that it implements Serializable.  The class attribute can be any fully qualified class name.  Wildcards are allowed.  You can also insert in $instanceof{ or an annotation expression i.e. @myannotation.

     

    Externalizable.  Using a Mixin

    The next example forces POJO2 to implement Externalizable.  Now, for this to work, POJO2 must implement the readExternal and writeExternal methods required by the Externalizable interface.  These methods are provided by the POJO2ExternalizableMixin class.  Take a look at the XML binding for this:

     

       <introduction class="POJO2">
          <mixin>
             <interfaces>
                java.io.Externalizable
             </interfaces>
             <class>POJO2ExternalizableMixin</class>
             <construction>new POJO2ExternalizableMixin(this)</construction>
          </mixin>
       </introduction>
    

     

    Most of this makes sense, but what is the tag allocates a POJO2ExternalizableMixin and passes in a this pointer.  The this pointer is actually the instance of the class that the Mixin is being applied to.  This allows the Mixin class to handle externalization.

     

    Complex Expressions

    The class attribute of the introduction can only handle a single class expression.  If you want a boolean expression, you can instead use the expr XML attribute.  You can have any scoped boolean expression.  The class(..) keyword will have a class expression within it.  You can also specify a has or hasField expression as well.  The example shows how to use the expr XML attribute.

     

       <annotation tag="test" class="POJO3">
          <method expr="void method()"></method>
       </annotation>
    
       <annotation tag="test2" class="POJO4">
          <class></class>
       </annotation>
    

     

    First we add some metadata to POJO3 and POJO4.  Then we use these tags in our introduction expression:

     

       <introduction expr="has(* *->@test(..)) OR class(@test2)">
          <interfaces>
             java.io.Serializable
          </interfaces>
       </introduction>
    

     

    The expr states:  Any class that has a method tagged as @test or any class that is itself tagged @test2.

     

    Running the example

    Driver.java drives the test.  It does serializable by using java.rmi.MarshalledObject to create a copy of POJO and POJO2 in memory.  The introductions will allow this code to work.

     

    First, try running the example without JBossAOP:

    $ rm *.class
    $ javac *.java
    $ java Driver
    

     

    You should see the following error:

     

    C:\jboss\jboss-head\aop\tmp\docs\examples\introductions>java Driver
    --- POJO ---
    Exception in thread "main" java.io.NotSerializableException: POJO
            at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1054)
            at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:278)
            at java.rmi.MarshalledObject.<init>(MarshalledObject.java:92)
            at Driver.main(Driver.java:8)
    

     

    This is expected because POJO is not serializable.  Now run it with introductions.

     

    $ ant
    

     

    The output should be:

     

    run:
         [java] --- POJO ---
         [java] deserialized pojo.stuff: hello world
         [java] --- POJO2 ---
         [java] deserialized pojo2.stuff2: hello world
         [java] --- POJO3 ---
         [java] pojo3 introduction expression worked
         [java] --- POJO4 ---
         [java] pojo4 introduction expression worked