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/04/07 23:16:54 UTC
svn commit: r1090018 - 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/ test/java/testinterfaces/
test/java/testsubjects/
Author: hlship
Date: Thu Apr 7 21:16:50 2011
New Revision: 1090018
URL: http://svn.apache.org/viewvc?rev=1090018&view=rev
Log:
TAP5-853: Add support for copying annotations from a source class to a PlasticClass, used in certain Tapestry IoC proxy creation scenarios
Added:
tapestry/tapestry5/trunk/plastic/src/test/java/testinterfaces/
tapestry/tapestry5/trunk/plastic/src/test/java/testinterfaces/AnnotationTransfer.java
tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/AnnotationTransferImpl.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/ProxyCreation.groovy
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=1090018&r1=1090017&r2=1090018&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 Thu Apr 7 21:16:50 2011
@@ -639,9 +639,9 @@ public class PlasticClassImpl extends Lo
// Easiest to load this, for the putField(), early, in case the field is
// wide (long or double primitive)
-
+
constructorBuilder.loadThis();
-
+
// Add the InstanceContext to the stack
constructorBuilder.loadArgument(1);
@@ -2213,4 +2213,94 @@ public class PlasticClassImpl extends Lo
return methodBundle.isImplemented(description.methodName, nameCache.toDesc(description));
}
+ public PlasticClass copyAnnotations(String sourceClassName)
+ {
+ assert PlasticInternalUtils.isNonBlank(sourceClassName);
+
+ ClassNode sourceClass = pool.constructClassNode(sourceClassName);
+
+ classNode.visibleAnnotations = sourceClass.visibleAnnotations;
+
+ Map<String, MethodNode> sourceMethods = buildMethodNodeMap(sourceClass, true);
+
+ if (sourceMethods.isEmpty())
+ return this;
+
+ Map<String, MethodNode> targetMethods = buildMethodNodeMap(classNode, false);
+
+ for (Map.Entry<String, MethodNode> entry : sourceMethods.entrySet())
+ {
+ MethodNode target = targetMethods.get(entry.getKey());
+
+ // Not all source methods (especially private ones) will be in the target class,
+ // which is typically a proxy, implementing just public methods defined in an interface.
+
+ if (target == null)
+ continue;
+
+ MethodNode source = entry.getValue();
+
+ target.visibleAnnotations = source.visibleAnnotations;
+ target.visibleParameterAnnotations = source.visibleParameterAnnotations;
+ }
+
+ return this;
+ }
+
+ private static Map<String, MethodNode> buildMethodNodeMap(ClassNode source, boolean withAnnotationsOnly)
+ {
+ boolean all = !withAnnotationsOnly;
+
+ Map<String, MethodNode> result = new HashMap<String, MethodNode>();
+
+ for (Object m : source.methods)
+ {
+ MethodNode mn = (MethodNode) m;
+
+ if (mn.name.equals(CONSTRUCTOR_NAME))
+ continue;
+
+ if (all || hasAnnotations(mn))
+ result.put(mn.name + ":" + mn.desc, mn);
+ }
+
+ return result;
+ }
+
+ /**
+ * 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)
+ {
+ if (nonEmpty(mn.visibleAnnotations))
+ return true;
+
+ if (mn.visibleParameterAnnotations != null)
+ {
+ for (List pa : mn.visibleParameterAnnotations)
+ {
+ if (nonEmpty(pa))
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private static boolean nonEmpty(List l)
+ {
+ return l != null && !l.isEmpty();
+ }
+
+ public PlasticClass copyAnnotations(Class sourceClass)
+ {
+ assert sourceClass != null;
+
+ return copyAnnotations(sourceClass.getName());
+ }
+
}
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=1090018&r1=1090017&r2=1090018&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 Thu Apr 7 21:16:50 2011
@@ -60,7 +60,7 @@ public class PlasticClassPool implements
protected TypeCategory convert(String typeName)
{
- ClassNode cn = createClassNode(typeName);
+ ClassNode cn = constructClassNode(typeName);
return Modifier.isInterface(cn.access) ? TypeCategory.INTERFACE : TypeCategory.CLASS;
}
@@ -267,7 +267,7 @@ public class PlasticClassPool implements
{
assert PlasticInternalUtils.isNonBlank(className);
- ClassNode classNode = createClassNode(className);
+ ClassNode classNode = constructClassNode(className);
String baseClassName = PlasticInternalUtils.toClassName(classNode.superName);
@@ -291,7 +291,15 @@ public class PlasticClassPool implements
return new PlasticClassImpl(classNode, this, emptyMethodBundle, emptyStaticContext);
}
- private ClassNode createClassNode(String className)
+ /**
+ * Constructs a class node by reading the raw bytecode for a class and instantiating a ClassNode
+ * (via {@link ClassReader#accept(org.apache.tapestry5.internal.plastic.asm.ClassVisitor, int)}).
+ *
+ * @param className
+ * fully qualified class name
+ * @return corresponding ClassNode
+ */
+ public ClassNode constructClassNode(String className)
{
byte[] bytecode = readBytecode(className);
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=1090018&r1=1090017&r2=1090018&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 Thu Apr 7 21:16:50 2011
@@ -149,4 +149,28 @@ public interface PlasticClass extends An
* @return this plastic class, for further configuration
*/
PlasticClass addToString(String toStringValue);
+
+ /**
+ * Copies annotations from the indicated source class name; this copies all class annotations,
+ * and for each method that exists in both classes, copies over method and parameter annotations. This addresses
+ * a specific use case for Tapestry IoC, where a proxy class is expected to expose the visible annotations of the
+ * implementation class. As currently implemented, copied annotations <em>overwrite</em> annotations in this
+ * PlasticClass (because it is expected that there are no annotations in a proxy).
+ * <p>
+ * This method should be invoked late in the PlasticClass transformation; copied annotations may not be visible as
+ * annotations on the PlasticClass or {@link PlasticMethod}s of the PlasticClass.
+ *
+ * @param sourceClassName
+ * source class from which to extract annotations
+ * @return this plastic class, for further configuration
+ */
+ PlasticClass copyAnnotations(String sourceClassName);
+
+ /**
+ * An convenience for {@link #copyAnnotations(String)}.
+ *
+ * @param sourceClass
+ * @return this plastic class, for further configuration
+ */
+ PlasticClass copyAnnotations(Class sourceClass);
}
Modified: tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/ProxyCreation.groovy
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/ProxyCreation.groovy?rev=1090018&r1=1090017&r2=1090018&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/ProxyCreation.groovy (original)
+++ tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/ProxyCreation.groovy Thu Apr 7 21:16:50 2011
@@ -1,6 +1,10 @@
package org.apache.tapestry5.plastic
-import spock.lang.Specification;
+import spock.lang.Specification
+import testannotations.Maybe
+import testannotations.Truth
+import testinterfaces.AnnotationTransfer
+import testsubjects.AnnotationTransferImpl
class ProxyCreation extends Specification {
def "create a proxy"() {
@@ -46,4 +50,25 @@ class ProxyCreation extends Specificatio
def e = thrown(IllegalArgumentException)
e.message == "Class java.lang.String is not an interface; proxies may only be created for interfaces."
}
+
+ def "copying of annotations"() {
+ setup:
+ def mgr = new PlasticManager()
+
+ def o = mgr.createProxy (AnnotationTransfer.class, { PlasticClass pc ->
+
+ pc.copyAnnotations (AnnotationTransferImpl.class)
+ } as PlasticClassTransformer).newInstance()
+
+ def oc = o.getClass()
+ def method1 = oc.getMethod("method1", int.class)
+
+ expect:
+
+ oc.getAnnotation(Maybe.class).value() == Truth.YES
+
+ method1.getAnnotation(Maybe.class).value() == Truth.YES
+ method1.getParameterAnnotations()[0][0].annotationType() == Maybe.class
+ method1.getParameterAnnotations()[0][0].value() == Truth.YES
+ }
}
Added: tapestry/tapestry5/trunk/plastic/src/test/java/testinterfaces/AnnotationTransfer.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/test/java/testinterfaces/AnnotationTransfer.java?rev=1090018&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/test/java/testinterfaces/AnnotationTransfer.java (added)
+++ tapestry/tapestry5/trunk/plastic/src/test/java/testinterfaces/AnnotationTransfer.java Thu Apr 7 21:16:50 2011
@@ -0,0 +1,14 @@
+package testinterfaces;
+
+import testannotations.Maybe;
+import testannotations.Truth;
+
+@Maybe(Truth.NO)
+public interface AnnotationTransfer
+{
+ @Maybe(Truth.NO)
+ void method1(@Maybe(Truth.NO)
+ int foo);
+
+ void method2(int bar);
+}
Added: tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/AnnotationTransferImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/AnnotationTransferImpl.java?rev=1090018&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/AnnotationTransferImpl.java (added)
+++ tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/AnnotationTransferImpl.java Thu Apr 7 21:16:50 2011
@@ -0,0 +1,33 @@
+package testsubjects;
+
+import testannotations.Maybe;
+import testannotations.Truth;
+import testinterfaces.AnnotationTransfer;
+
+@Maybe(Truth.YES)
+public class AnnotationTransferImpl implements AnnotationTransfer
+{
+
+ @Maybe(Truth.YES)
+ public void method1(@Maybe(Truth.YES)
+ int foo)
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void method2(@Maybe(Truth.YES)
+ int bar)
+ {
+ }
+
+ @Maybe(Truth.YES)
+ public void notInInterfaceMethod()
+ {
+ }
+
+ protected void hasNoAnnotationsMethod()
+ {
+ }
+
+}