Author: hlship
Date: Fri Dec 23 18:55:06 2011
New Revision: 1222790
URL: http://svn.apache.org/viewvc?rev=1222790&view=rev
Log:
TAP5-1801: Allow non-public fields in instrumented classes
Support field instrumentation on accesses from inner classes
Added:
tapestry/tapestry5/trunk/plastic/src/test/java/testinterfaces/ValueGetter.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/ClassType.java
tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/FieldAccessTests.groovy
tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/ProtectedField.java
tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/ProtectedFieldCollaborator.java
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=1222790&r1=1222789&r2=1222790&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
Fri Dec 23 18:55:06 2011
@@ -714,9 +714,6 @@ public class PlasticClassImpl extends Lo
interceptFieldAccess(node);
}
-
- // Remove all added methods that aren't actually used.
-
}
/**
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=1222790&r1=1222789&r2=1222790&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
Fri Dec 23 18:55:06 2011
@@ -17,8 +17,7 @@ package org.apache.tapestry5.internal.pl
import org.apache.tapestry5.internal.plastic.asm.ClassReader;
import org.apache.tapestry5.internal.plastic.asm.ClassWriter;
import org.apache.tapestry5.internal.plastic.asm.Opcodes;
-import org.apache.tapestry5.internal.plastic.asm.tree.AnnotationNode;
-import org.apache.tapestry5.internal.plastic.asm.tree.ClassNode;
+import org.apache.tapestry5.internal.plastic.asm.tree.*;
import org.apache.tapestry5.plastic.*;
import java.lang.annotation.Annotation;
@@ -129,7 +128,7 @@ public class PlasticClassPool implements
}
- public Class realize(String primaryClassName, ClassType classType, final
ClassNode classNode)
+ public Class realize(String primaryClassName, ClassType classType,
ClassNode classNode)
{
synchronized (loader)
{
@@ -315,7 +314,9 @@ public class PlasticClassPool implements
// Inner classes are not transformed, but they are loaded by the same
class loader.
if (className.contains("$"))
+ {
return loadInnerClass(className);
+ }
// TODO: What about interfaces, enums, annotations, etc. ... they
shouldn't be in the package, but
// we should generate a reasonable error message.
@@ -360,11 +361,56 @@ public class PlasticClassPool implements
private Class loadInnerClass(String className)
{
- byte[] bytecode = readBytecode(className);
+ ClassNode classNode = constructClassNodeFromBytecode(className);
- return loader.defineClassWithBytecode(className, bytecode);
+ interceptFieldAccess(classNode);
+
+ return realize(className, ClassType.INNER, classNode);
}
+ private void interceptFieldAccess(ClassNode classNode)
+ {
+ for (MethodNode method : (List<MethodNode>) classNode.methods) {
+ interceptFieldAccess(classNode.name, method);
+ }
+ }
+
+ private void interceptFieldAccess(String classInternalName, MethodNode
method)
+ {
+ InsnList insns = method.instructions;
+
+ ListIterator it = insns.iterator();
+
+ while (it.hasNext())
+ {
+ AbstractInsnNode node = (AbstractInsnNode) it.next();
+
+ int opcode = node.getOpcode();
+
+ if (opcode != GETFIELD && opcode != PUTFIELD)
+ {
+ continue;
+ }
+
+ FieldInsnNode fnode = (FieldInsnNode) node;
+
+ String ownerInternalName = fnode.owner;
+
+ if (ownerInternalName.equals(classInternalName)) { continue; }
+
+ FieldInstrumentation instrumentation =
getFieldInstrumentations(ownerInternalName).get(fnode.name, opcode == GETFIELD);
+
+ if (instrumentation == null) { continue; }
+
+ // Replace the field access node with the appropriate method
invocation.
+
+ insns.insertBefore(fnode, new MethodInsnNode(INVOKEVIRTUAL,
ownerInternalName, instrumentation.methodName,
instrumentation.methodDescription));
+
+ it.remove();
+ }
+ }
+
+
/**
* For a fully-qualified class name of an <em>existing</em> class, loads
the bytes for the class
* and returns a PlasticClass instance.
@@ -388,8 +434,8 @@ public class PlasticClassPool implements
/**
*
* @param baseClassName class from which the transformed class extends
- * @param classNode node for the class
- * @param proxy if true, the class is a new empty class; if false an
existing class that's being transformed
+ * @param classNode node for the class
+ * @param proxy if true, the class is a new empty class; if false
an existing class that's being transformed
* @return
* @throws ClassNotFoundException
*/
Modified:
tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/ClassType.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/ClassType.java?rev=1222790&r1=1222789&r2=1222790&view=diff
==============================================================================
---
tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/ClassType.java
(original)
+++
tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/ClassType.java
Fri Dec 23 18:55:06 2011
@@ -33,5 +33,13 @@ public enum ClassType
* An implementation of {@link MethodInvocation}, needed to handle advice
added to
* a method of a primary class.
*/
- METHOD_INVOCATION
+ METHOD_INVOCATION,
+
+ /**
+ * An inner class within a controlled package, which may have field
accesses (to non-private
+ * fields visible to it) instrumented.
+ *
+ * @since 5.4
+ */
+ INNER;
}
Modified:
tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/FieldAccessTests.groovy
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/FieldAccessTests.groovy?rev=1222790&r1=1222789&r2=1222790&view=diff
==============================================================================
---
tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/FieldAccessTests.groovy
(original)
+++
tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/FieldAccessTests.groovy
Fri Dec 23 18:55:06 2011
@@ -1,5 +1,8 @@
package org.apache.tapestry5.plastic
+import testannotations.KindaInject
+import testannotations.SimpleAnnotation
+
/**
* Tests related to access to non-private fields between transformed classes
(a new feature in 5.4).
*/
@@ -38,4 +41,37 @@ class FieldAccessTests extends AbstractP
collab.getProtectedValue() == "badoop"
}
+
+ def "access protected field from inner class"()
+ {
+
+ FieldConduit fc = Mock()
+
+ def delegate
+
+ PlasticClassTransformer installFieldConduit = { PlasticClass pc ->
+
+ pc.getFieldsWithAnnotation(SimpleAnnotation.class).each { f ->
f.setConduit(fc) }
+
+ } as PlasticClassTransformer
+
+ PlasticClassTransformer handleInjection = { PlasticClass pc ->
+
+ pc.getFieldsWithAnnotation(KindaInject.class).each { f ->
f.inject(delegate) }
+ } as PlasticClassTransformer
+
+ def mgr = createMgr(installFieldConduit, handleInjection)
+
+ delegate =
mgr.getClassInstantiator("testsubjects.ProtectedField").newInstance()
+
+ def collab =
mgr.getClassInstantiator("testsubjects.ProtectedFieldCollaborator").newInstance()
+
+ when:
+
+ fc.get(_, _) >> "gnip"
+
+ then:
+
+ collab.valueGetter.value == "gnip"
+ }
}
Added:
tapestry/tapestry5/trunk/plastic/src/test/java/testinterfaces/ValueGetter.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/test/java/testinterfaces/ValueGetter.java?rev=1222790&view=auto
==============================================================================
---
tapestry/tapestry5/trunk/plastic/src/test/java/testinterfaces/ValueGetter.java
(added)
+++
tapestry/tapestry5/trunk/plastic/src/test/java/testinterfaces/ValueGetter.java
Fri Dec 23 18:55:06 2011
@@ -0,0 +1,6 @@
+package testinterfaces;
+
+public interface ValueGetter
+{
+ String getValue();
+}
Modified:
tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/ProtectedField.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/ProtectedField.java?rev=1222790&r1=1222789&r2=1222790&view=diff
==============================================================================
---
tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/ProtectedField.java
(original)
+++
tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/ProtectedField.java
Fri Dec 23 18:55:06 2011
@@ -1,9 +1,12 @@
package testsubjects;
+import testannotations.SimpleAnnotation;
+
/**
* Used to test access to protected fields. Accessed from {@link
ProtectedFieldCollaborator}.
*/
public class ProtectedField
{
+ @SimpleAnnotation
protected String protectedValue;
}
Modified:
tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/ProtectedFieldCollaborator.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/ProtectedFieldCollaborator.java?rev=1222790&r1=1222789&r2=1222790&view=diff
==============================================================================
---
tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/ProtectedFieldCollaborator.java
(original)
+++
tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/ProtectedFieldCollaborator.java
Fri Dec 23 18:55:06 2011
@@ -1,8 +1,12 @@
package testsubjects;
+import testannotations.KindaInject;
+import testinterfaces.ValueGetter;
+
public class ProtectedFieldCollaborator
{
- private ProtectedField delegate;
+ @KindaInject
+ ProtectedField delegate;
public String getProtectedValue()
{
@@ -13,4 +17,15 @@ public class ProtectedFieldCollaborator
{
delegate.protectedValue = newValue;
}
+
+ public ValueGetter getValueGetter()
+ {
+ return new ValueGetter()
+ {
+ public String getValue()
+ {
+ return delegate.protectedValue;
+ }
+ };
+ }
}