You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pivot.apache.org by tv...@apache.org on 2009/05/07 01:33:59 UTC

svn commit: r772466 - in /incubator/pivot/trunk: build.xml wtk/src/pivot/wtkx/BindProcessor.java wtk/src/pivot/wtkx/Bindable.java

Author: tvolkert
Date: Wed May  6 23:33:59 2009
New Revision: 772466

URL: http://svn.apache.org/viewvc?rev=772466&view=rev
Log:
Made the bind processor generate code that works with inheritance chains

Modified:
    incubator/pivot/trunk/build.xml
    incubator/pivot/trunk/wtk/src/pivot/wtkx/BindProcessor.java
    incubator/pivot/trunk/wtk/src/pivot/wtkx/Bindable.java

Modified: incubator/pivot/trunk/build.xml
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/build.xml?rev=772466&r1=772465&r2=772466&view=diff
==============================================================================
--- incubator/pivot/trunk/build.xml (original)
+++ incubator/pivot/trunk/build.xml Wed May  6 23:33:59 2009
@@ -374,7 +374,7 @@
             target="${compiler.target}"
             encoding="${compiler.encoding}"
             failonerror="true">
-            <compilerarg value="-Xlint"/>
+            <compilerarg line="-Xlint -processor pivot.wtkx.BindProcessor"/>
             <classpath>
                 <pathelement location="core/${folder.bin}"/>
                 <fileset dir="wtk/lib" includes="**/*.jar"/>

Modified: incubator/pivot/trunk/wtk/src/pivot/wtkx/BindProcessor.java
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/wtk/src/pivot/wtkx/BindProcessor.java?rev=772466&r1=772465&r2=772466&view=diff
==============================================================================
--- incubator/pivot/trunk/wtk/src/pivot/wtkx/BindProcessor.java (original)
+++ incubator/pivot/trunk/wtk/src/pivot/wtkx/BindProcessor.java Wed May  6 23:33:59 2009
@@ -52,9 +52,6 @@
  * Annotation processor that injects <tt>bind()</tt> overrides into classes
  * that use the <tt>@Load</tt> and <tt>@Bind</tt> annotations to perform WTKX
  * loading and binding.
- * <p>
- * TODO Make base bind() final, and strip out that flag at compilation time
- * to allow us to extend it.
  *
  * @author tvolkert
  */
@@ -62,6 +59,11 @@
 @SupportedSourceVersion(SourceVersion.RELEASE_6)
 public class BindProcessor extends AbstractProcessor {
     /**
+     * Holds pertinent information about a class' member variables that use
+     * the <tt>@Load</tt> and <tt>@Bind</tt> annotations. A bind scope object
+     * is pushed onto a stack before visiting a class and popped off the
+     * stack after visiting it, allowing us to know if any members variables
+     * contained in the class need bind processing as we're exiting the class.
      *
      * @author tvolkert
      */
@@ -80,13 +82,21 @@
     }
 
     /**
-     * This actually does the work of instance initializer injection.
+     * This actually does the work of bind method override injection.
      *
      * @author tvolkert
      */
     private class BindInjector extends TreeTranslator {
         private ArrayStack<BindScope> bindScopeStack = new ArrayStack<BindScope>();
 
+        /**
+         * Injects an override implementation of the <tt>bind()</tt> method
+         * into the specified class if any member variables are found to be
+         * annotated with the <tt>@Load</tt> or <tt>@Bind</tt> annotations.
+         *
+         * @param tree
+         * The AST class declaration node
+         */
         @Override
         public void visitClassDef(JCTree.JCClassDecl tree) {
             BindScope bindScope = new BindScope();
@@ -98,8 +108,11 @@
             if (bindScope.loadGroups != null) {
                 StringBuilder sourceCode = new StringBuilder("{");
 
-                // TODO Call super.bind() once impl stripping is being done
-                // on the base class' implementation
+                sourceCode.append("try {");
+                sourceCode.append("super.bind();");
+                sourceCode.append("} catch (Exception ex) {");
+                sourceCode.append("throw new pivot.wtkx.BindException(ex);");
+                sourceCode.append("}");
                 sourceCode.append("pivot.wtkx.WTKXSerializer wtkxSerializer;");
                 sourceCode.append("Object value;");
 
@@ -166,6 +179,8 @@
                 JCTree.JCBlock methodBody = parser.block();
 
                 // Create the bind() override AST method declaration
+                // TODO Declare it to throw IOException, then remove the
+                // try/catch from super.bind()
                 Type.MethodType methodType = new Type.MethodType(
                     List.<Type>nil(),             // Argument types
                     symbolTable.voidType,         // Return type
@@ -188,6 +203,44 @@
             }
         }
 
+        /**
+         * Checks for the <tt>@BindMethod</tt> annotation on a method
+         * (signalling the base class' implementation). When found, this strips
+         * the method of its body and the <tt>final</tt> keyword, thus clearing
+         * the way for us to override <tt>bind()</tt> in bindable subclasses
+         * with inline implementations that can safely call
+         * <tt>super.bind()</tt> without running the runtime bind
+         * implementation.
+         *
+         * @param tree
+         * The AST method declaration node
+         */
+        @Override
+        public void visitMethodDef(JCTree.JCMethodDecl tree) {
+            super.visitMethodDef(tree);
+
+            Element methodElement = tree.sym;
+            Bindable.BindMethod bindMethod = methodElement.getAnnotation(Bindable.BindMethod.class);
+
+            if (bindMethod != null) {
+                // Remove the 'final' flag so that we may extend the method
+                tree.sym.flags_field &= ~Flags.FINAL;
+                tree.mods.flags &= ~Flags.FINAL;
+
+                // Clear the method body so that it becomes a no-op
+                tree.body.stats = List.<JCTree.JCStatement>nil();
+            }
+        }
+
+        /**
+         * Looks for the <tt>@Load</tt> and <tt>@Bind</tt> annotations on
+         * member variable declarations. When found, it records pertinent
+         * information in the current bind scope, to be used before we exit
+         * the containing class.
+         *
+         * @param tree
+         * The AST variable declaration node
+         */
         @Override
         public void visitVarDef(JCTree.JCVariableDecl tree) {
             super.visitVarDef(tree);
@@ -269,7 +322,7 @@
         if (!roundEnvironment.processingOver()) {
             for (Element rootElement : roundEnvironment.getRootElements()) {
                 if (rootElement.getKind() == ElementKind.CLASS) {
-                    // Visit each Class tree with our bindInjector visitor
+                    // Visit each AST class node with our BindInjector visitor
                     JCTree tree = (JCTree)trees.getTree(rootElement);
                     tree.accept(bindInjector);
                 }

Modified: incubator/pivot/trunk/wtk/src/pivot/wtkx/Bindable.java
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/wtk/src/pivot/wtkx/Bindable.java?rev=772466&r1=772465&r2=772466&view=diff
==============================================================================
--- incubator/pivot/trunk/wtk/src/pivot/wtkx/Bindable.java (original)
+++ incubator/pivot/trunk/wtk/src/pivot/wtkx/Bindable.java Wed May  6 23:33:59 2009
@@ -64,9 +64,24 @@
     }
 
     /**
+     * Flags the base implementation of the bind method. This cues the
+     * annotation processor to remove the <tt>final</tt> flag from the method
+     * so that it may be extended by the compiler and to remove the body of the
+     * method, making it a no-op at runtime (since the annotation processor
+     * inlines all WTKX binding).
+     *
+     * @author tvolkert
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @Target(ElementType.METHOD)
+    static @interface BindMethod {
+    }
+
+    /**
      * Applies WTKX binding annotations to this bindable object.
      */
-    protected void bind() throws IOException, BindException {
+    @BindMethod
+    protected final void bind() throws IOException, BindException {
         // Walk fields and resolve annotations
         ArrayList<Class<?>> typeHierarchy = new ArrayList<Class<?>>();
         Class<?> type = getClass();