You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2012/04/13 00:20:08 UTC
svn commit: r1325552 - in /tapestry/tapestry5/branches/5.3/plastic/src:
main/java/org/apache/tapestry5/internal/plastic/
test/groovy/org/apache/tapestry5/plastic/
Author: hlship
Date: Thu Apr 12 22:20:08 2012
New Revision: 1325552
URL: http://svn.apache.org/viewvc?rev=1325552&view=rev
Log:
TAP5-1860: Access to protected component fields does not always reflect in subclasses
Modified:
tapestry/tapestry5/branches/5.3/plastic/src/main/java/org/apache/tapestry5/internal/plastic/FieldInstrumentations.java
tapestry/tapestry5/branches/5.3/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassImpl.java
tapestry/tapestry5/branches/5.3/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassPool.java
tapestry/tapestry5/branches/5.3/plastic/src/test/groovy/org/apache/tapestry5/plastic/FieldConduitTests.groovy
Modified: tapestry/tapestry5/branches/5.3/plastic/src/main/java/org/apache/tapestry5/internal/plastic/FieldInstrumentations.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/branches/5.3/plastic/src/main/java/org/apache/tapestry5/internal/plastic/FieldInstrumentations.java?rev=1325552&r1=1325551&r2=1325552&view=diff
==============================================================================
--- tapestry/tapestry5/branches/5.3/plastic/src/main/java/org/apache/tapestry5/internal/plastic/FieldInstrumentations.java (original)
+++ tapestry/tapestry5/branches/5.3/plastic/src/main/java/org/apache/tapestry5/internal/plastic/FieldInstrumentations.java Thu Apr 12 22:20:08 2012
@@ -1,4 +1,4 @@
-// Copyright 2011 The Apache Software Foundation
+// Copyright 2011, 2012 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -24,6 +24,8 @@ import java.util.Map;
*/
class FieldInstrumentations
{
+ final String superClassInternalName;
+
/**
* Map field name to a read method.
*/
@@ -34,6 +36,11 @@ class FieldInstrumentations
*/
final Map<String, FieldInstrumentation> write = PlasticInternalUtils.newMap();
+ FieldInstrumentations(String superClassInternalName)
+ {
+ this.superClassInternalName = superClassInternalName;
+ }
+
FieldInstrumentation get(String fieldName, boolean forRead)
{
Map<String, FieldInstrumentation> map = forRead ? read : write;
Modified: tapestry/tapestry5/branches/5.3/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/branches/5.3/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassImpl.java?rev=1325552&r1=1325551&r2=1325552&view=diff
==============================================================================
--- tapestry/tapestry5/branches/5.3/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassImpl.java (original)
+++ tapestry/tapestry5/branches/5.3/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassImpl.java Thu Apr 12 22:20:08 2012
@@ -1,4 +1,4 @@
-// Copyright 2011 The Apache Software Foundation
+// Copyright 2011, 2012 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -138,7 +138,7 @@ public class PlasticClassImpl extends Lo
* Tracks instrumentations of fields of this class, including private fields which are not published into the
* {@link PlasticClassPool}.
*/
- private final FieldInstrumentations fieldInstrumentations = new FieldInstrumentations();
+ private final FieldInstrumentations fieldInstrumentations;
/**
* This normal no-arguments constructor, or null. By the end of the transformation
@@ -186,6 +186,8 @@ public class PlasticClassImpl extends Lo
className = PlasticInternalUtils.toClassName(classNode.name);
superClassName = PlasticInternalUtils.toClassName(classNode.superName);
+ fieldInstrumentations = new FieldInstrumentations(classNode.superName);
+
annotationAccess = new DelegatingAnnotationAccess(pool.createAnnotationAccess(classNode.visibleAnnotations),
pool.createAnnotationAccess(superClassName));
@@ -909,9 +911,12 @@ public class PlasticClassImpl extends Lo
FieldInsnNode fnode = (FieldInsnNode) node;
- FieldInstrumentation instrumentation = findInstrumentations(fnode).get(fnode.name, opcode == GETFIELD);
+ FieldInstrumentation instrumentation = findFieldNodeInstrumentation(fnode, opcode == GETFIELD);
- if (instrumentation == null) { continue; }
+ if (instrumentation == null)
+ {
+ continue;
+ }
// Replace the field access node with the appropriate method invocation.
@@ -921,15 +926,29 @@ public class PlasticClassImpl extends Lo
}
}
- private FieldInstrumentations findInstrumentations(FieldInsnNode node)
+ private FieldInstrumentation findFieldNodeInstrumentation(FieldInsnNode node, boolean forRead)
{
- if (node.owner.equals(classNode.name))
+ // First look in the local fieldInstrumentations, which contains private field instrumentations
+ // (as well as non-private ones).
+
+ String searchStart = node.owner;
+
+ if (searchStart.equals(classNode.name))
{
- return fieldInstrumentations;
- }
+ FieldInstrumentation result = fieldInstrumentations.get(node.name, forRead);
+
+ if (result != null)
+ {
+ return result;
+ }
+
+ // Slight optimization: start the search in the super-classes' fields, since we've already
+ // checked this classes fields.
- return pool.getFieldInstrumentations(node.owner);
+ searchStart = classNode.superName;
+ }
+ return pool.getFieldInstrumentation(searchStart, node.name, forRead);
}
String getInstanceContextFieldName()
Modified: tapestry/tapestry5/branches/5.3/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassPool.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/branches/5.3/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassPool.java?rev=1325552&r1=1325551&r2=1325552&view=diff
==============================================================================
--- tapestry/tapestry5/branches/5.3/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassPool.java (original)
+++ tapestry/tapestry5/branches/5.3/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassPool.java Thu Apr 12 22:20:08 2012
@@ -1,4 +1,4 @@
-// Copyright 2011 The Apache Software Foundation
+// Copyright 2011, 2012 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -86,7 +86,7 @@ public class PlasticClassPool implements
private final Map<String, FieldInstrumentations> instrumentations = PlasticInternalUtils.newMap();
- private final FieldInstrumentations placeholder = new FieldInstrumentations();
+ private final FieldInstrumentations placeholder = new FieldInstrumentations(null);
private final Set<TransformationOption> options;
@@ -370,7 +370,8 @@ public class PlasticClassPool implements
private void interceptFieldAccess(ClassNode classNode)
{
- for (MethodNode method : (List<MethodNode>) classNode.methods) {
+ for (MethodNode method : (List<MethodNode>) classNode.methods)
+ {
interceptFieldAccess(classNode.name, method);
}
}
@@ -396,11 +397,17 @@ public class PlasticClassPool implements
String ownerInternalName = fnode.owner;
- if (ownerInternalName.equals(classInternalName)) { continue; }
+ if (ownerInternalName.equals(classInternalName))
+ {
+ continue;
+ }
- FieldInstrumentation instrumentation = getFieldInstrumentations(ownerInternalName).get(fnode.name, opcode == GETFIELD);
+ FieldInstrumentation instrumentation = getFieldInstrumentation(ownerInternalName, fnode.name, opcode == GETFIELD);
- if (instrumentation == null) { continue; }
+ if (instrumentation == null)
+ {
+ continue;
+ }
// Replace the field access node with the appropriate method invocation.
@@ -426,13 +433,12 @@ public class PlasticClassPool implements
String baseClassName = PlasticInternalUtils.toClassName(classNode.superName);
- instrumentations.put(classNode.name, new FieldInstrumentations());
+ instrumentations.put(classNode.name, new FieldInstrumentations(classNode.superName));
return createTransformation(baseClassName, classNode, false);
}
/**
- *
* @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
@@ -582,7 +588,8 @@ public class PlasticClassPool implements
instrumentations.get(classInternalName).read.put(fieldName, fi);
}
- FieldInstrumentations getFieldInstrumentations(String classInternalName)
+
+ private FieldInstrumentations getFieldInstrumentations(String classInternalName)
{
FieldInstrumentations result = instrumentations.get(classInternalName);
@@ -620,6 +627,32 @@ public class PlasticClassPool implements
return result;
}
+ FieldInstrumentation getFieldInstrumentation(String ownerClassInternalName, String fieldName, boolean forRead)
+ {
+ String currentName = ownerClassInternalName;
+
+ while (true)
+ {
+
+ if (currentName == null)
+ {
+ return null;
+ }
+
+ FieldInstrumentations instrumentations = getFieldInstrumentations(currentName);
+
+ FieldInstrumentation instrumentation = instrumentations.get(fieldName, forRead);
+
+ if (instrumentation != null)
+ {
+ return instrumentation;
+ }
+
+ currentName = instrumentations.superClassInternalName;
+ }
+ }
+
+
void setFieldWriteInstrumentation(String classInternalName, String fieldName, FieldInstrumentation fi)
{
instrumentations.get(classInternalName).write.put(fieldName, fi);
Modified: tapestry/tapestry5/branches/5.3/plastic/src/test/groovy/org/apache/tapestry5/plastic/FieldConduitTests.groovy
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/branches/5.3/plastic/src/test/groovy/org/apache/tapestry5/plastic/FieldConduitTests.groovy?rev=1325552&r1=1325551&r2=1325552&view=diff
==============================================================================
--- tapestry/tapestry5/branches/5.3/plastic/src/test/groovy/org/apache/tapestry5/plastic/FieldConduitTests.groovy (original)
+++ tapestry/tapestry5/branches/5.3/plastic/src/test/groovy/org/apache/tapestry5/plastic/FieldConduitTests.groovy Thu Apr 12 22:20:08 2012
@@ -118,6 +118,37 @@ class FieldConduitTests extends Abstract
1 * fc.get(o, _) >> "plastic"
}
+ def "subclass access methods are reouted through field conduit"()
+ {
+ FieldConduit fc = Mock()
+
+ def mgr = PlasticManager.withContextClassLoader().delegate(
+ [
+ transform: { PlasticClass pc ->
+ pc.allFields.each { f -> f.setConduit(fc) }
+ },
+ configureInstantiator: { className, instantiator -> instantiator }
+ ] as PlasticManagerDelegate).packages(["testsubjects"]).create()
+
+ def o = mgr.getClassInstantiator(ProtectedFieldSubclass.class.name).newInstance()
+
+ when:
+
+ o.value = "wink"
+
+ then:
+
+ 1 * fc.set(o, _, "wink")
+
+ when:
+
+ assert o.value == "bumble"
+
+ then:
+
+ 1* fc.get(o, _) >> "bumble"
+ }
+
def "verify writebehind on normal field"()
{
FieldConduit fc = Mock()