You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2011/07/25 20:03:25 UTC

svn commit: r1150816 - in /tapestry/tapestry5/trunk/plastic/src: main/java/org/apache/tapestry5/internal/plastic/ main/java/org/apache/tapestry5/plastic/ test/groovy/org/apache/tapestry5/plastic/

Author: hlship
Date: Mon Jul 25 18:03:24 2011
New Revision: 1150816

URL: http://svn.apache.org/viewvc?rev=1150816&view=rev
Log:
Rename MethodBundle to InheritanceData
Add PlasticClass.isInterfaceImplemented()

Added:
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/InheritanceData.java
      - copied, changed from r1150815, tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/MethodBundle.java
Removed:
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/MethodBundle.java
Modified:
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassImpl.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassPool.java
    tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticClass.java
    tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/MethodIntroduction.groovy

Copied: tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/InheritanceData.java (from r1150815, tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/MethodBundle.java)
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/InheritanceData.java?p2=tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/InheritanceData.java&p1=tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/MethodBundle.java&r1=1150815&r2=1150816&rev=1150816&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/MethodBundle.java (original)
+++ tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/InheritanceData.java Mon Jul 25 18:03:24 2011
@@ -14,36 +14,34 @@
 
 package org.apache.tapestry5.internal.plastic;
 
-import java.util.Collection;
-import java.util.HashSet;
 import java.util.Set;
 
 /**
  * Used to track which methods are implemented by a base class, which is often needed when transforming
  * a subclass.
  */
-public class MethodBundle
+public class InheritanceData
 {
-    private final MethodBundle parent;
+    private final InheritanceData parent;
 
     private final Set<String> methodNames = PlasticInternalUtils.newSet();
     private final Set<String> methods = PlasticInternalUtils.newSet();
+    private final Set<String> interfaceNames = PlasticInternalUtils.newSet();
 
-    public MethodBundle()
+    public InheritanceData()
     {
         this(null);
     }
 
-    private MethodBundle(MethodBundle parent)
+    private InheritanceData(InheritanceData parent)
     {
         this.parent = parent;
     }
 
     /**
      * Is this bundle for a transformed class, or for a base class (typically Object)?
-     * 
-     * @return
-     *         true if this bundle is for transformed class, false otherwise
+     *
+     * @return true if this bundle is for transformed class, false otherwise
      */
     public boolean isTransformed()
     {
@@ -53,24 +51,21 @@ public class MethodBundle
     /**
      * Returns a new MethodBundle that represents the methods of a child class
      * of this bundle. The returned bundle will always be {@linkplain #isTransformed() transformed}.
-     * 
-     * @param childClassName
-     *            name of subclass
+     *
+     * @param childClassName name of subclass
      * @return new method bundle
      */
-    public MethodBundle createChild(String childClassName)
+    public InheritanceData createChild(String childClassName)
     {
-        return new MethodBundle(this);
+        return new InheritanceData(this);
     }
 
     /**
      * Adds a new instance method. Only non-private, non-abstract methods should be added (that is, methods which might
      * be overridden in subclasses). This can later be queried to see if any base class implements the method.
-     * 
-     * @param name
-     *            name of method
-     * @param desc
-     *            method descriptor
+     *
+     * @param name name of method
+     * @param desc method descriptor
      */
     public void addMethod(String name, String desc)
     {
@@ -82,11 +77,9 @@ public class MethodBundle
 
     /**
      * Returns true if a transformed parent class contains the indicated method.
-     * 
-     * @param name
-     *            method name
-     * @param desc
-     *            method descriptor
+     *
+     * @param name method name
+     * @param desc method descriptor
      * @return the <em>internal name</em> of the implementing base class for this method,
      *         or null if no base class implements the method
      */
@@ -95,6 +88,7 @@ public class MethodBundle
         return checkForMethod(toValue(name, desc));
     }
 
+
     private boolean checkForMethod(String value)
     {
         if (methods.contains(value))
@@ -104,6 +98,31 @@ public class MethodBundle
     }
 
     /**
+     * Returns true if the class represented by this data, or any parent data, implements
+     * the named interface.
+     */
+    public boolean isInterfaceImplemented(String name)
+    {
+        InheritanceData cursor = this;
+
+        while (cursor != null)
+        {
+            if (cursor.interfaceNames.contains(name))
+            {
+                return true;
+            }
+
+            cursor = cursor.parent;
+        }
+
+        return false;
+    }
+
+    public void addInterface(String name) {
+        interfaceNames.add(name);
+    }
+
+    /**
      * Combines a method name and its desc (which describes parameter types and return value) to form
      * a value, which is how methods are tracked.
      */
@@ -119,7 +138,7 @@ public class MethodBundle
     {
         Set<String> result = PlasticInternalUtils.newSet();
 
-        MethodBundle cursor = this;
+        InheritanceData cursor = this;
 
         while (cursor != null)
         {

Modified: tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassImpl.java?rev=1150816&r1=1150815&r2=1150816&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassImpl.java (original)
+++ tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassImpl.java Mon Jul 25 18:03:24 2011
@@ -188,7 +188,7 @@ public class PlasticClassImpl extends Lo
         {
             check();
 
-            return parentMethodBundle.isImplemented(node.name, node.desc);
+            return parentInheritanceData.isImplemented(node.name, node.desc);
         }
 
         public String getMethodIdentifier()
@@ -794,7 +794,7 @@ public class PlasticClassImpl extends Lo
 
             String desc = nameCache.toDesc(description);
 
-            if (methodBundle.isImplemented(name, desc))
+            if (inheritanceData.isImplemented(name, desc))
                 throw new IllegalArgumentException(String.format(
                         "Unable to create new accessor method %s on class %s as the method is already implemented.",
                         description.toString(), className));
@@ -1045,7 +1045,7 @@ public class PlasticClassImpl extends Lo
 
         private final ClassNode invocationClassNode;
 
-        private final List<MethodAdvice> advice = new ArrayList<MethodAdvice>();
+        private final List<MethodAdvice> advice = PlasticInternalUtils.newList();
 
         private final boolean isVoid;
 
@@ -1095,7 +1095,7 @@ public class PlasticClassImpl extends Lo
                 invocationClassNode.visitField(ACC_PUBLIC, RETURN_VALUE, nameCache.toDesc(description.returnType),
                         null, null);
 
-            List<String> consTypes = new ArrayList<String>();
+            List<String> consTypes = PlasticInternalUtils.newList();
             consTypes.add(Object.class.getName());
             consTypes.add(InstanceContext.class.getName());
             consTypes.add(MethodInvocationBundle.class.getName());
@@ -1450,7 +1450,7 @@ public class PlasticClassImpl extends Lo
 
     private final Set<String> methodNames = new HashSet<String>();
 
-    private final List<ConstructorCallback> constructorCallbacks = new ArrayList<ConstructorCallback>();
+    private final List<ConstructorCallback> constructorCallbacks = PlasticInternalUtils.newList();
 
     // All non-introduced instance fields
 
@@ -1472,7 +1472,7 @@ public class PlasticClassImpl extends Lo
 
     private final StaticContext staticContext;
 
-    private final MethodBundle parentMethodBundle, methodBundle;
+    private final InheritanceData parentInheritanceData, inheritanceData;
 
     // MethodNodes in which field transformations should occur; this is most existing and
     // introduced methods, outside of special access methods.
@@ -1525,10 +1525,10 @@ public class PlasticClassImpl extends Lo
     /**
      * @param classNode
      * @param pool
-     * @param parentMethodBundle
+     * @param parentInheritanceData
      * @param parentStaticContext
      */
-    public PlasticClassImpl(ClassNode classNode, PlasticClassPool pool, MethodBundle parentMethodBundle,
+    public PlasticClassImpl(ClassNode classNode, PlasticClassPool pool, InheritanceData parentInheritanceData,
                             StaticContext parentStaticContext)
     {
         this.classNode = classNode;
@@ -1542,8 +1542,13 @@ public class PlasticClassImpl extends Lo
         annotationAccess = new DelegatingAnnotationAccess(pool.createAnnotationAccess(classNode.visibleAnnotations),
                 pool.createAnnotationAccess(superClassName));
 
-        this.parentMethodBundle = parentMethodBundle;
-        methodBundle = parentMethodBundle.createChild(className);
+        this.parentInheritanceData = parentInheritanceData;
+        inheritanceData = parentInheritanceData.createChild(className);
+
+        for (String interfaceName : (List<String>) classNode.interfaces)
+        {
+            inheritanceData.addInterface(interfaceName);
+        }
 
         methods = new ArrayList(classNode.methods.size());
 
@@ -1575,7 +1580,7 @@ public class PlasticClassImpl extends Lo
             {
                 if (!Modifier.isPrivate(node.access))
                 {
-                    methodBundle.addMethod(node.name, node.desc);
+                    inheritanceData.addMethod(node.name, node.desc);
                 }
 
                 methodNames.add(node.name);
@@ -1594,12 +1599,12 @@ public class PlasticClassImpl extends Lo
             description2method.put(pmi.getDescription(), pmi);
 
             if (isInheritableMethod(node))
-                methodBundle.addMethod(node.name, node.desc);
+                inheritanceData.addMethod(node.name, node.desc);
 
             methodNames.add(node.name);
         }
 
-        methodNames.addAll(parentMethodBundle.methodNames());
+        methodNames.addAll(parentInheritanceData.methodNames());
 
         Collections.sort(methods);
 
@@ -1637,7 +1642,7 @@ public class PlasticClassImpl extends Lo
 
         // Start by calling the super-class no args constructor
 
-        if (parentMethodBundle.isTransformed())
+        if (parentInheritanceData.isTransformed())
         {
             // If the parent is transformed, our first step is always to invoke its constructor.
 
@@ -1706,7 +1711,7 @@ public class PlasticClassImpl extends Lo
 
         completeConstructor();
 
-        transformedClass = pool.realizeTransformedClass(classNode, methodBundle, staticContext);
+        transformedClass = pool.realizeTransformedClass(classNode, inheritanceData, staticContext);
 
         return createInstantiatorFromClass(transformedClass);
     }
@@ -2004,7 +2009,7 @@ public class PlasticClassImpl extends Lo
         methodNames.add(methodNode.name);
 
         if (!Modifier.isPrivate(methodNode.access))
-            methodBundle.addMethod(methodNode.name, methodNode.desc);
+            inheritanceData.addMethod(methodNode.name, methodNode.desc);
     }
 
     private PlasticMethod createNewMethod(MethodDescription description)
@@ -2024,7 +2029,7 @@ public class PlasticClassImpl extends Lo
 
         MethodNode methodNode = new MethodNode(description.modifiers, description.methodName, desc,
                 description.genericSignature, exceptions);
-        boolean isOverride = methodBundle.isImplemented(methodNode.name, desc);
+        boolean isOverride = inheritanceData.isImplemented(methodNode.name, desc);
 
         if (isOverride)
             createOverrideOfBaseClassImpl(description, methodNode);
@@ -2413,10 +2418,11 @@ public class PlasticClassImpl extends Lo
 
         String interfaceName = nameCache.toInternalName(interfaceType);
 
-        // I suppose this means that a subclass may restate that it implements an interface from a base class.
-
-        if (!classNode.interfaces.contains(interfaceName))
+        if (!inheritanceData.isInterfaceImplemented(interfaceName))
+        {
             classNode.interfaces.add(interfaceName);
+            inheritanceData.addInterface(interfaceName);
+        }
 
         Set<PlasticMethod> introducedMethods = new HashSet<PlasticMethod>();
 
@@ -2453,36 +2459,17 @@ public class PlasticClassImpl extends Lo
 
     public boolean isMethodImplemented(MethodDescription description)
     {
-        return methodBundle.isImplemented(description.methodName, nameCache.toDesc(description));
+        return inheritanceData.isImplemented(description.methodName, nameCache.toDesc(description));
     }
 
-    /**
-     * True if the node has any visible annotations, or it has visible annotations on any
-     * parameter.
-     *
-     * @param mn
-     * @return true if any annotations present
-     */
-    private static boolean hasAnnotations(MethodNode mn)
+    public boolean isInterfaceImplemented(Class interfaceType)
     {
-        if (nonEmpty(mn.visibleAnnotations))
-            return true;
-
-        if (mn.visibleParameterAnnotations != null)
-        {
-            for (List pa : mn.visibleParameterAnnotations)
-            {
-                if (nonEmpty(pa))
-                    return true;
-            }
-        }
+        assert interfaceType != null;
+        assert interfaceType.isInterface();
 
-        return false;
-    }
+        String interfaceName = nameCache.toInternalName(interfaceType);
 
-    private static boolean nonEmpty(List l)
-    {
-        return l != null && !l.isEmpty();
+        return inheritanceData.isInterfaceImplemented(interfaceName);
     }
 
     public String getSuperClassName()

Modified: tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassPool.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassPool.java?rev=1150816&r1=1150815&r2=1150816&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassPool.java (original)
+++ tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassPool.java Mon Jul 25 18:03:24 2011
@@ -54,7 +54,7 @@ public class PlasticClassPool implements
 
     private final Map<String, ClassInstantiator> instantiators = PlasticInternalUtils.newMap();
 
-    private final MethodBundle emptyMethodBundle = new MethodBundle();
+    private final InheritanceData emptyInheritanceData = new InheritanceData();
 
     private final StaticContext emptyStaticContext = new StaticContext();
 
@@ -73,13 +73,13 @@ public class PlasticClassPool implements
 
     static class BaseClassDef
     {
-        final MethodBundle methodBundle;
+        final InheritanceData inheritanceData;
 
         final StaticContext staticContext;
 
-        public BaseClassDef(MethodBundle methodBundle, StaticContext staticContext)
+        public BaseClassDef(InheritanceData inheritanceData, StaticContext staticContext)
         {
-            this.methodBundle = methodBundle;
+            this.inheritanceData = inheritanceData;
             this.staticContext = staticContext;
         }
     }
@@ -116,12 +116,12 @@ public class PlasticClassPool implements
         return loader;
     }
 
-    public synchronized Class realizeTransformedClass(ClassNode classNode, MethodBundle methodBundle,
+    public synchronized Class realizeTransformedClass(ClassNode classNode, InheritanceData inheritanceData,
             StaticContext staticContext)
     {
         Class result = realize(PlasticInternalUtils.toClassName(classNode.name), ClassType.PRIMARY, classNode);
 
-        baseClassDefs.put(result.getName(), new BaseClassDef(methodBundle, staticContext));
+        baseClassDefs.put(result.getName(), new BaseClassDef(inheritanceData, staticContext));
 
         return result;
     }
@@ -363,10 +363,10 @@ public class PlasticClassPool implements
 
             assert def != null;
 
-            return new PlasticClassImpl(classNode, this, def.methodBundle, def.staticContext);
+            return new PlasticClassImpl(classNode, this, def.inheritanceData, def.staticContext);
         }
 
-        return new PlasticClassImpl(classNode, this, emptyMethodBundle, emptyStaticContext);
+        return new PlasticClassImpl(classNode, this, emptyInheritanceData, emptyStaticContext);
     }
 
     /**

Modified: tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticClass.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticClass.java?rev=1150816&r1=1150815&r2=1150816&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticClass.java (original)
+++ tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticClass.java Mon Jul 25 18:03:24 2011
@@ -182,6 +182,14 @@ public interface PlasticClass extends An
     boolean isMethodImplemented(MethodDescription description);
 
     /**
+     * Returns true if this class, or a super-class, implements the indicated interface.
+     *
+     * @param interfaceType
+     * @return true if the interface is implemented
+     */
+    boolean isInterfaceImplemented(Class interfaceType);
+
+    /**
      * Returns the name of the super-class of the class being transformed.
      */
     String getSuperClassName();

Modified: tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/MethodIntroduction.groovy
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/MethodIntroduction.groovy?rev=1150816&r1=1150815&r2=1150816&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/MethodIntroduction.groovy (original)
+++ tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/MethodIntroduction.groovy Mon Jul 25 18:03:24 2011
@@ -1,15 +1,18 @@
 package org.apache.tapestry5.plastic
 
 
-class MethodIntroduction extends AbstractPlasticSpecification {
+class MethodIntroduction extends AbstractPlasticSpecification
+{
 
     static final String CLASS_NAME = "testsubjects.ChildClass"
 
-    def instanceWithIntroducedMethod(MethodDescription md, isOverride) {
-        def mgr = createMgr ({ PlasticClass pc ->
-            if (pc.className == CLASS_NAME) {
+    def instanceWithIntroducedMethod(MethodDescription md, isOverride)
+    {
+        def mgr = createMgr({ PlasticClass pc ->
+            if (pc.className == CLASS_NAME)
+            {
                 def method = pc.introduceMethod(md)
-                
+
                 assert method.override == isOverride
             }
         } as PlasticClassTransformer)
@@ -17,7 +20,8 @@ class MethodIntroduction extends Abstrac
         return mgr.getClassInstantiator(CLASS_NAME).newInstance()
     }
 
-    def "introduce method not present in base class"() {
+    def "introduce method not present in base class"()
+    {
 
         def o = instanceWithIntroducedMethod(new MethodDescription(returnType, methodName), false)
 
@@ -38,19 +42,20 @@ class MethodIntroduction extends Abstrac
 
         where:
 
-        returnType          | methodName    | access             | expectedValue    | expectedType
+        returnType         | methodName  | access             | expectedValue | expectedType
 
-        "java.lang.String"  | "getString"   | { it.getString() } | null             | null
-        "java.util.Date[]"  | "getDates"    | { it.getDates() }  | null             | null
-        "int"               | "getInt"      | { it.getInt() }    | 0                | Integer.class
-        "int[]"             | "getInts"     | { it.getInts() }   | null             | null
-        "char"              | "getChar"     | { it.getChar() }   | 0                | Character.class
-        "float"             | "getFloat"    | { it.getFloat() }  | 0f               | Float.class
-        "long"              | "getLong"     | { it.getLong() }   | 0l               | Long.class
-        "double"            | "getDouble"   | { it.getDouble() } | 0d               | Double.class
+        "java.lang.String" | "getString" | { it.getString() } | null          | null
+        "java.util.Date[]" | "getDates"  | { it.getDates() }  | null          | null
+        "int"              | "getInt"    | { it.getInt() }    | 0             | Integer.class
+        "int[]"            | "getInts"   | { it.getInts() }   | null          | null
+        "char"             | "getChar"   | { it.getChar() }   | 0             | Character.class
+        "float"            | "getFloat"  | { it.getFloat() }  | 0f            | Float.class
+        "long"             | "getLong"   | { it.getLong() }   | 0l            | Long.class
+        "double"           | "getDouble" | { it.getDouble() } | 0d            | Double.class
     }
 
-    def "introduce void method override"() {
+    def "introduce void method override"()
+    {
 
         setup:
 
@@ -65,28 +70,31 @@ class MethodIntroduction extends Abstrac
         true
     }
 
-    def "introduce primitive method override"() {
+    def "introduce primitive method override"()
+    {
         setup:
 
-        def o = instanceWithIntroducedMethod (new MethodDescription("int", "primitiveMethod", "int"), true)
+        def o = instanceWithIntroducedMethod(new MethodDescription("int", "primitiveMethod", "int"), true)
 
         expect:
 
         o.primitiveMethod(97) == 97
     }
 
-    def "introduce object method override"() {
+    def "introduce object method override"()
+    {
 
         setup:
 
-        def o = instanceWithIntroducedMethod (new MethodDescription("java.lang.String", "objectMethod", "java.lang.String"), true)
+        def o = instanceWithIntroducedMethod(new MethodDescription("java.lang.String", "objectMethod", "java.lang.String"), true)
 
         expect:
 
         o.objectMethod("plastic") == "plastic"
     }
 
-    def "introduce interface"() {
+    def "introduce interface"()
+    {
 
         def introduced
 
@@ -110,5 +118,35 @@ class MethodIntroduction extends Abstrac
         introduced.size() == 1
         introduced[0].methodName == "run"
     }
+
+    def "check for introduced interface is visible in subclasses"()
+    {
+        setup:
+
+        boolean present;
+
+        def mgr = createMgr({
+            PlasticClass pc ->
+            if (pc.className.contains("Base"))
+            {
+                pc.introduceInterface(Serializable.class)
+            }
+
+            if (pc.className.contains("Child"))
+            {
+                present = pc.isInterfaceImplemented(Serializable.class)
+            }
+
+        } as PlasticClassTransformer)
+
+        when:
+
+        mgr.getClassInstantiator("testsubjects.ChildClass")
+
+        then:
+
+        present == true
+    }
+
 }