Author: hlship
Date: Fri Nov 30 12:35:56 2007
New Revision: 599949

URL: http://svn.apache.org/viewvc?rev=599949&view=rev
Log:
TAPESTRY-1843: Fields not rewritten when modifying existing methods

Added:
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app2/PlusOne.java
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/MethodPrefixTarget.java
Modified:
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformation.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformationImpl.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/ClassTransformation.java
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app2/pages/TestPrefixMethod.java
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app2/services/LocaleAppModule.java
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/pagelevel/PrefixMethodTest.java
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/InternalClassTransformationImplTest.java
    
tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry/integration/app2/pages/TestPrefixMethod.tml

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformation.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformation.java?rev=599949&r1=599948&r2=599949&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformation.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformation.java
 Fri Nov 30 12:35:56 2007
@@ -28,12 +28,6 @@
 public interface InternalClassTransformation extends ClassTransformation
 {
     /**
-     * Returns the name of the protected field that is injected with the
-     * [EMAIL PROTECTED] 
org.apache.tapestry.internal.InternalComponentResources}.
-     */
-    String getResourcesFieldName();
-
-    /**
      * Invoked after all [EMAIL PROTECTED] ComponentClassTransformWorker}s 
have had their chance to work over
      * the class. This performs any final operations for the class 
transformation, which includes
      * coming up with the final constructor method for the class.

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformationImpl.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformationImpl.java?rev=599949&r1=599948&r2=599949&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformationImpl.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformationImpl.java
 Fri Nov 30 12:35:56 2007
@@ -113,8 +113,7 @@
     private ClassLoader _loader;
 
     /**
-     * This is a constructor for the root class, the class that directly 
contains the ComponentClass
-     * annotation.
+     * This is a constructor for a base class.
      */
     public InternalClassTransformationImpl(CtClass ctClass, ClassLoader 
loader, Logger logger,
                                            ComponentModel componentModel)
@@ -143,8 +142,13 @@
                                                                     
"getComponentResources", null, null);
 
         addMethod(sig, "return " + _resourcesFieldName + ";");
+
+        // The "}" will be added later, inside  finish().
     }
 
+    /**
+     * Constructor for a component sub-class.
+     */
     public InternalClassTransformationImpl(CtClass ctClass, 
InternalClassTransformation parentTransformation,
                                            ClassLoader loader, Logger logger, 
ComponentModel componentModel)
     {
@@ -184,7 +188,7 @@
 
         _constructor.append(");\n");
 
-        // The "}" will be added later, inside
+        // The "}" will be added later, inside  finish().
     }
 
     private void freeze()
@@ -622,11 +626,31 @@
         _addedMethods.add(method);
     }
 
+    public void extendExistingMethod(TransformMethodSignature methodSignature, 
String methodBody)
+    {
+        failIfFrozen();
+
+        CtMethod method = findMethod(methodSignature);
+
+        try
+        {
+            method.insertAfter(methodBody);
+        }
+        catch (CannotCompileException ex)
+        {
+            throw new 
MethodCompileException(ServicesMessages.methodCompileError(methodSignature, 
methodBody, ex),
+                                             methodBody, ex);
+        }
+
+        addMethodToDescription("extend existing", methodSignature, methodBody);
+    }
+
     public void prefixMethod(TransformMethodSignature methodSignature, String 
methodBody)
     {
         failIfFrozen();
 
         CtMethod method = findMethod(methodSignature);
+
         try
         {
             method.insertBefore(methodBody);
@@ -638,7 +662,6 @@
         }
 
         addMethodToDescription("prefix", methodSignature, methodBody);
-        _addedMethods.add(method);
     }
 
     private void addMethodToDescription(String operation, 
TransformMethodSignature methodSignature, String methodBody)
@@ -1383,15 +1406,32 @@
             @Override
             public void edit(FieldAccess access) throws CannotCompileException
             {
+                boolean isRead = access.isReader();
+                String fieldName = access.getFieldName();
+                CtBehavior where = access.where();
+
+                _formatter.format("Checking field %s %s in %s: ", isRead ? 
"read" : "write", fieldName,
+                                  where.getLongName());
+
                 // Ignore any methods to were added as part of the 
transformation.
                 // If we reference the field there, we really mean the field.
 
-                if (_addedMethods.contains(access.where())) return;
+                if (_addedMethods.contains(where))
+                {
+                    _formatter.format("added method\n");
+                    return;
+                }
 
-                Map<String, String> transformMap = access.isReader() ? 
_fieldReadTransforms : _fieldWriteTransforms;
+                Map<String, String> transformMap = isRead ? 
_fieldReadTransforms : _fieldWriteTransforms;
 
-                String body = transformMap.get(access.getFieldName());
-                if (body == null) return;
+                String body = transformMap.get(fieldName);
+                if (body == null)
+                {
+                    _formatter.format("field not transformed\n");
+                    return;
+                }
+
+                _formatter.format("replacing with %s\n", body);
 
                 access.replace(body);
             }
@@ -1405,6 +1445,8 @@
         {
             throw new RuntimeException(ex);
         }
+
+        _formatter.format("\n");
     }
 
     public Class toClass(String type)

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/ClassTransformation.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/ClassTransformation.java?rev=599949&r1=599948&r2=599949&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/ClassTransformation.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/ClassTransformation.java
 Fri Nov 30 12:35:56 2007
@@ -227,24 +227,47 @@
      * inherited methods, a method is added that first invokes the super 
implementation. Use
      * [EMAIL PROTECTED] #addMethod(TransformMethodSignature, String)} when it 
is necessary to control when the
      * super-class method is invoked.
+     * <p/>
+     * The extended method is considered <em>new</em>. New methods <em>do 
not</em> are not
+     * scanned for [EMAIL PROTECTED] #removeField(String)} removed}, [EMAIL 
PROTECTED] #replaceReadAccess(String, String)} read replaced},
+     * or [EMAIL PROTECTED] #replaceWriteAccess(String, String) write 
replaced} fields.  Generally that's what you want!
      *
      * @param methodSignature the signature of the method to extend
      * @param methodBody      the body of code
-     * @throws IllegalArgumentException if the provided Javassist method body 
can not be compiled
+     * @throws org.apache.tapestry.internal.services.MethodCompileException
+     *          if the provided Javassist method body can not be compiled
+     * @see #extendExistingMethod(TransformMethodSignature, String)
      */
     void extendMethod(TransformMethodSignature methodSignature, String 
methodBody);
 
     /**
+     * Like [EMAIL PROTECTED] #extendMethod(TransformMethodSignature, 
String)}, but the extension does not mark
+     * the method as new, and field changes <em>will</em> be processed.
+     *
+     * @param methodSignature signature of the method to extend
+     * @param methodBody      the body of code
+     * @throws org.apache.tapestry.internal.services.MethodCompileException
+     *          if the provided method body can not be compiled
+     * @see #prefixMethod(TransformMethodSignature, String)
+     */
+    void extendExistingMethod(TransformMethodSignature methodSignature, String 
methodBody);
+
+    /**
      * Inserts code at the beginning of a method body (i.e. [EMAIL PROTECTED] 
CtBehavior#insertBefore(String)}.
      * <p/>
      * The method may be declared in the class, or may be inherited from a 
super-class. For
      * inherited methods, a method is added that first invokes the super 
implementation. Use
      * [EMAIL PROTECTED] #addMethod(TransformMethodSignature, String)} when it 
is necessary to control when the
      * super-class method is invoked.
+     * <p/>
+     * <p/>
+     * Like [EMAIL PROTECTED] #extendExistingMethod(TransformMethodSignature, 
String)}, this method is generally used to "wrap" an existing method adding 
additional functionality
+     * such as caching or transaction support.
      *
      * @param methodSignature
      * @param methodBody
-     * @throws IllegalArgumentException If the provided Javassist method body 
could not be compiled
+     * @throws org.apache.tapestry.internal.services.MethodCompileException
+     *          if the provided method body can not be compiled
      */
     void prefixMethod(TransformMethodSignature methodSignature, String 
methodBody);
 

Added: 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app2/PlusOne.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app2/PlusOne.java?rev=599949&view=auto
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app2/PlusOne.java
 (added)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app2/PlusOne.java
 Fri Nov 30 12:35:56 2007
@@ -0,0 +1,32 @@
+// Copyright 2007 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.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry.integration.app2;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ * Adds 1 to a method result. Testing only.
+ */
[EMAIL PROTECTED](ElementType.METHOD)
[EMAIL PROTECTED](RUNTIME)
[EMAIL PROTECTED]
+public @interface PlusOne
+{
+
+}

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app2/pages/TestPrefixMethod.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app2/pages/TestPrefixMethod.java?rev=599949&r1=599948&r2=599949&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app2/pages/TestPrefixMethod.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app2/pages/TestPrefixMethod.java
 Fri Nov 30 12:35:56 2007
@@ -14,7 +14,12 @@
 
 package org.apache.tapestry.integration.app2.pages;
 
+import org.apache.tapestry.ComponentResources;
+import org.apache.tapestry.annotations.InjectPage;
 import org.apache.tapestry.integration.app2.FortyTwo;
+import org.apache.tapestry.integration.app2.PlusOne;
+import org.apache.tapestry.ioc.annotations.Inject;
+import org.apache.tapestry.services.BeanModelSource;
 
 public class TestPrefixMethod
 {
@@ -24,4 +29,28 @@
         return 0;
     }
 
+    @Inject
+    private ComponentResources _resources;
+
+    @Inject
+    private BeanModelSource _modelSource;
+
+    @InjectPage
+    private TestPrefixMethod2 _otherPage;
+
+    private int foo;
+
+    @FortyTwo
+    public int getValue2()
+    {
+        foo = _modelSource.hashCode();
+        return foo;
+    }
+
+    @PlusOne
+    public int getValue3()
+    {
+        int value = _otherPage.hashCode();
+        return value * 0;
+    }
 }

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app2/services/LocaleAppModule.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app2/services/LocaleAppModule.java?rev=599949&r1=599948&r2=599949&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app2/services/LocaleAppModule.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app2/services/LocaleAppModule.java
 Fri Nov 30 12:35:56 2007
@@ -15,6 +15,7 @@
 package org.apache.tapestry.integration.app2.services;
 
 import org.apache.tapestry.integration.app2.FortyTwo;
+import org.apache.tapestry.integration.app2.PlusOne;
 import org.apache.tapestry.ioc.MappedConfiguration;
 import org.apache.tapestry.ioc.OrderedConfiguration;
 import org.apache.tapestry.model.MutableComponentModel;
@@ -24,8 +25,7 @@
 
 public class LocaleAppModule
 {
-    public static void contributeApplicationDefaults(
-            MappedConfiguration<String, String> configuration)
+    public static void 
contributeApplicationDefaults(MappedConfiguration<String, String> configuration)
     {
         configuration.add("tapestry.supported-locales", "en,fr,de");
     }
@@ -34,6 +34,7 @@
             OrderedConfiguration<ComponentClassTransformWorker> configuration)
     {
         configuration.add("FortyTwo", new FortyTwoWorker());
+        configuration.add("PlusOne", new PlusOneWorker());
     }
 
     private static final class FortyTwoWorker implements 
ComponentClassTransformWorker
@@ -47,5 +48,16 @@
             }
         }
 
+    }
+
+    private static final class PlusOneWorker implements 
ComponentClassTransformWorker
+    {
+        public void transform(ClassTransformation transformation, 
MutableComponentModel model)
+        {
+            for (TransformMethodSignature method : 
transformation.findMethodsWithAnnotation(PlusOne.class))
+            {
+                transformation.extendExistingMethod(method, "return $_ + 1;");
+            }
+        }
     }
 }

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/pagelevel/PrefixMethodTest.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/pagelevel/PrefixMethodTest.java?rev=599949&r1=599948&r2=599949&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/pagelevel/PrefixMethodTest.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/pagelevel/PrefixMethodTest.java
 Fri Nov 30 12:35:56 2007
@@ -33,7 +33,9 @@
         _tester = new PageTester(appPackage, appName, 
PageTester.DEFAULT_CONTEXT_PATH, LocaleAppModule.class);
         Document doc = _tester.renderPage("TestPrefixMethod");
 
-        assertEquals(doc.getElementById("value").getChildMarkup(), "42");
+        // make sure you can use on methods that have injected fields
+        assertEquals(doc.getElementById("value2").getChildMarkup(), "42");
+        assertEquals(doc.getElementById("value3").getChildMarkup(), "1");
 
         // should override the method in the superclass
         doc = _tester.renderPage("TestPrefixMethod2");

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/InternalClassTransformationImplTest.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/InternalClassTransformationImplTest.java?rev=599949&r1=599948&r2=599949&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/InternalClassTransformationImplTest.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/InternalClassTransformationImplTest.java
 Fri Nov 30 12:35:56 2007
@@ -23,8 +23,8 @@
 import org.apache.tapestry.internal.test.InternalBaseTestCase;
 import org.apache.tapestry.internal.transform.InheritedAnnotation;
 import org.apache.tapestry.internal.transform.pages.*;
-import org.apache.tapestry.ioc.internal.services.PropertyAccessImpl;
 import org.apache.tapestry.ioc.services.PropertyAccess;
+import org.apache.tapestry.ioc.util.BodyBuilder;
 import org.apache.tapestry.runtime.Component;
 import org.apache.tapestry.runtime.ComponentResourcesAware;
 import org.apache.tapestry.services.ClassTransformation;
@@ -176,9 +176,8 @@
         }
         catch (RuntimeException ex)
         {
-            assertEquals(
-                    ex.getMessage(),
-                    "Class 
org.apache.tapestry.internal.transform.pages.ParentClass does not contain a 
field named 'unknownField'.");
+            assertEquals(ex.getMessage(),
+                         "Class 
org.apache.tapestry.internal.transform.pages.ParentClass does not contain a 
field named 'unknownField'.");
         }
 
         verify();
@@ -323,9 +322,8 @@
         }
         catch (RuntimeException ex)
         {
-            assertEquals(
-                    ex.getMessage(),
-                    "Field _field4 of class 
org.apache.tapestry.internal.transform.pages.ClaimedFields is already claimed 
by Fred and can not be claimed by Barney.");
+            assertEquals(ex.getMessage(),
+                         "Field _field4 of class 
org.apache.tapestry.internal.transform.pages.ClaimedFields is already claimed 
by Fred and can not be claimed by Barney.");
         }
 
         verify();
@@ -387,9 +385,7 @@
 
         replay();
 
-        ClassTransformation ct = createClassTransformation(
-                ChildClassInheritsAnnotation.class,
-                logger);
+        ClassTransformation ct = 
createClassTransformation(ChildClassInheritsAnnotation.class, logger);
 
         InheritedAnnotation ia = ct.getAnnotation(InheritedAnnotation.class);
 
@@ -428,8 +424,7 @@
     }
 
     @Test
-    public void 
ensure_javassist_does_not_show_interface_methods_on_abstract_class()
-            throws Exception
+    public void 
ensure_javassist_does_not_show_interface_methods_on_abstract_class() throws 
Exception
     {
         CtClass ctClass = findCtClass(AbstractFoo.class);
 
@@ -449,8 +444,7 @@
     }
 
     @Test
-    public void 
ensure_javassist_does_not_show_extended_interface_methods_on_interface()
-            throws Exception
+    public void 
ensure_javassist_does_not_show_extended_interface_methods_on_interface() throws 
Exception
     {
         CtClass ctClass = findCtClass(FooBarInterface.class);
 
@@ -473,8 +467,8 @@
 
         replay();
 
-        InternalClassTransformation ct = new 
InternalClassTransformationImpl(targetObjectCtClass,
-                                                                             
_contextClassLoader, logger, null);
+        InternalClassTransformation ct = new 
InternalClassTransformationImpl(targetObjectCtClass, _contextClassLoader,
+                                                                             
logger, null);
 
         // Default behavior is to add an injected field for the 
InternalComponentResources object,
         // so we'll just check that.
@@ -505,8 +499,8 @@
 
         replay();
 
-        InternalClassTransformation ct = new 
InternalClassTransformationImpl(targetObjectCtClass,
-                                                                             
_loader, logger, null);
+        InternalClassTransformation ct = new 
InternalClassTransformationImpl(targetObjectCtClass, _loader, logger,
+                                                                             
null);
 
         String parentFieldName = ct.addInjectedField(String.class, "_value", 
value);
 
@@ -534,8 +528,8 @@
 
         // This proves the the field is protected and can be used in 
subclasses.
 
-        ct.addMethod(new TransformMethodSignature(Modifier.PUBLIC, 
"java.lang.String", "getValue",
-                                                  null, null), "return " + 
subclassFieldName + ";");
+        ct.addMethod(new TransformMethodSignature(Modifier.PUBLIC, 
"java.lang.String", "getValue", null, null),
+                     "return " + subclassFieldName + ";");
 
         ct.finish();
 
@@ -561,8 +555,8 @@
 
         replay();
 
-        InternalClassTransformation ct = new 
InternalClassTransformationImpl(ctClass,
-                                                                             
_contextClassLoader, logger, null);
+        InternalClassTransformation ct = new 
InternalClassTransformationImpl(ctClass, _contextClassLoader, logger,
+                                                                             
null);
 
         _classPool.toClass(ctClass, _loader);
 
@@ -573,9 +567,8 @@
         }
         catch (IllegalArgumentException ex)
         {
-            assertEquals(ex.getMessage(), 
ServicesMessages.incorrectClassForInstantiator(
-                    BasicComponent.class.getName(),
-                    Boolean.class));
+            assertEquals(ex.getMessage(),
+                         
ServicesMessages.incorrectClassForInstantiator(BasicComponent.class.getName(), 
Boolean.class));
         }
 
         verify();
@@ -592,8 +585,8 @@
 
         replay();
 
-        InternalClassTransformation ct = new 
InternalClassTransformationImpl(targetObjectCtClass,
-                                                                             
_contextClassLoader, logger, null);
+        InternalClassTransformation ct = new 
InternalClassTransformationImpl(targetObjectCtClass, _contextClassLoader,
+                                                                             
logger, null);
 
         ct.addImplementedInterface(FooInterface.class);
         ct.addImplementedInterface(GetterMethodsInterface.class);
@@ -604,8 +597,7 @@
 
         Class[] interfaces = transformed.getInterfaces();
 
-        assertEquals(interfaces, new Class[]
-                {Component.class, FooInterface.class, 
GetterMethodsInterface.class});
+        assertEquals(interfaces, new Class[]{Component.class, 
FooInterface.class, GetterMethodsInterface.class});
 
         Object target = 
ct.createInstantiator(transformed).newInstance(resources);
 
@@ -640,31 +632,26 @@
 
         CtClass targetObjectCtClass = findCtClass(ReadOnlyBean.class);
 
-        InternalClassTransformation ct = new 
InternalClassTransformationImpl(targetObjectCtClass,
-                                                                             
_contextClassLoader, logger, null);
+        InternalClassTransformation ct = new 
InternalClassTransformationImpl(targetObjectCtClass, _contextClassLoader,
+                                                                             
logger, null);
 
         ct.makeReadOnly("_value");
 
         ct.finish();
 
-        Class transformed = _classPool.toClass(targetObjectCtClass, _loader);
-
-        Object target = 
ct.createInstantiator(transformed).newInstance(resources);
-
-        PropertyAccess access = new PropertyAccessImpl();
+        Object target = instantiate(ReadOnlyBean.class, ct, resources);
 
         try
         {
-            access.set(target, "value", "anything");
+            _access.set(target, "value", "anything");
             unreachable();
         }
         catch (RuntimeException ex)
         {
             // The PropertyAccess layer adds a wrapper exception around the 
real one.
 
-            assertEquals(
-                    ex.getCause().getMessage(),
-                    "Field 
org.apache.tapestry.internal.services.ReadOnlyBean._value is read-only.");
+            assertEquals(ex.getCause().getMessage(),
+                         "Field 
org.apache.tapestry.internal.services.ReadOnlyBean._value is read-only.");
         }
 
         verify();
@@ -679,8 +666,8 @@
 
         CtClass targetObjectCtClass = findCtClass(RemoveFieldBean.class);
 
-        InternalClassTransformation ct = new 
InternalClassTransformationImpl(targetObjectCtClass,
-                                                                             
_contextClassLoader, logger, null);
+        InternalClassTransformation ct = new 
InternalClassTransformationImpl(targetObjectCtClass, _contextClassLoader,
+                                                                             
logger, null);
 
         ct.removeField("_barney");
 
@@ -700,20 +687,16 @@
 
         CtClass targetObjectCtClass = findCtClass(ReadOnlyBean.class);
 
-        InternalClassTransformation ct = new 
InternalClassTransformationImpl(targetObjectCtClass,
-                                                                             
_contextClassLoader, logger, null);
+        InternalClassTransformation ct = new 
InternalClassTransformationImpl(targetObjectCtClass, _contextClassLoader,
+                                                                             
logger, null);
 
         ct.extendConstructor("_value = \"from constructor\";");
 
         ct.finish();
 
-        Class transformed = _classPool.toClass(targetObjectCtClass, _loader);
-
-        Object target = 
ct.createInstantiator(transformed).newInstance(resources);
-
-        PropertyAccess access = new PropertyAccessImpl();
+        Object target = instantiate(ReadOnlyBean.class, ct, resources);
 
-        assertEquals(access.get(target, "value"), "from constructor");
+        assertEquals(_access.get(target, "value"), "from constructor");
 
         verify();
     }
@@ -729,33 +712,28 @@
 
         CtClass targetObjectCtClass = findCtClass(ReadOnlyBean.class);
 
-        InternalClassTransformation ct = new 
InternalClassTransformationImpl(targetObjectCtClass,
-                                                                             
_contextClassLoader, logger, null);
+        InternalClassTransformation ct = new 
InternalClassTransformationImpl(targetObjectCtClass, _contextClassLoader,
+                                                                             
logger, null);
 
         ct.injectField("_value", "Tapestry");
 
         ct.finish();
 
-        Class transformed = _classPool.toClass(targetObjectCtClass, _loader);
-
-        Object target = 
ct.createInstantiator(transformed).newInstance(resources);
-
-        PropertyAccess access = new PropertyAccessImpl();
+        Object target = instantiate(ReadOnlyBean.class, ct, resources);
 
-        assertEquals(access.get(target, "value"), "Tapestry");
+        assertEquals(_access.get(target, "value"), "Tapestry");
 
         try
         {
-            access.set(target, "value", "anything");
+            _access.set(target, "value", "anything");
             unreachable();
         }
         catch (RuntimeException ex)
         {
             // The PropertyAccess layer adds a wrapper exception around the 
real one.
 
-            assertEquals(
-                    ex.getCause().getMessage(),
-                    "Field 
org.apache.tapestry.internal.services.ReadOnlyBean._value is read-only.");
+            assertEquals(ex.getCause().getMessage(),
+                         "Field 
org.apache.tapestry.internal.services.ReadOnlyBean._value is read-only.");
         }
 
         verify();
@@ -776,8 +754,8 @@
 
         CtClass targetObjectCtClass = findCtClass(FieldAccessBean.class);
 
-        InternalClassTransformation ct = new 
InternalClassTransformationImpl(targetObjectCtClass,
-                                                                             
_contextClassLoader, logger, null);
+        InternalClassTransformation ct = new 
InternalClassTransformationImpl(targetObjectCtClass, _contextClassLoader,
+                                                                             
logger, null);
 
         replaceAccessToField(ct, "foo");
         replaceAccessToField(ct, "bar");
@@ -786,27 +764,23 @@
 
         ct.finish();
 
-        Class transformed = _classPool.toClass(targetObjectCtClass, _loader);
-
-        Object target = 
ct.createInstantiator(transformed).newInstance(resources);
+        Object target = instantiate(FieldAccessBean.class, ct, resources);
 
         // target is no longer assignable to FieldAccessBean; its a new class 
from a new class
         // loader. So we use reflective access, which doesn't care about such 
things.
 
-        PropertyAccess access = new PropertyAccessImpl();
-
-        checkReplacedFieldAccess(access, target, "foo");
-        checkReplacedFieldAccess(access, target, "bar");
+        checkReplacedFieldAccess(target, "foo");
+        checkReplacedFieldAccess(target, "bar");
 
         verify();
     }
 
-    private void checkReplacedFieldAccess(PropertyAccess access, Object 
target, String propertyName)
+    private void checkReplacedFieldAccess(Object target, String propertyName)
     {
 
         try
         {
-            access.get(target, propertyName);
+            _access.get(target, propertyName);
             unreachable();
         }
         catch (RuntimeException ex)
@@ -817,7 +791,7 @@
 
         try
         {
-            access.set(target, propertyName, "new value");
+            _access.set(target, propertyName, "new value");
             unreachable();
         }
         catch (RuntimeException ex)
@@ -832,23 +806,20 @@
         String fieldName = "_" + baseName;
         String readMethodName = "_read_" + baseName;
 
-        TransformMethodSignature readMethodSignature = new 
TransformMethodSignature(
-                Modifier.PRIVATE, STRING_CLASS_NAME, readMethodName, null, 
null);
+        TransformMethodSignature readMethodSignature = new 
TransformMethodSignature(Modifier.PRIVATE, STRING_CLASS_NAME,
+                                                                               
     readMethodName, null, null);
 
-        ct.addMethod(readMethodSignature, String.format(
-                "throw new RuntimeException(\"read %s\");",
-                baseName));
+        ct.addMethod(readMethodSignature, String.format("throw new 
RuntimeException(\"read %s\");", baseName));
 
         ct.replaceReadAccess(fieldName, readMethodName);
 
         String writeMethodName = "_write_" + baseName;
 
-        TransformMethodSignature writeMethodSignature = new 
TransformMethodSignature(
-                Modifier.PRIVATE, "void", writeMethodName, new String[]
-                {STRING_CLASS_NAME}, null);
-        ct.addMethod(writeMethodSignature, String.format(
-                "throw new RuntimeException(\"write %s\");",
-                baseName));
+        TransformMethodSignature writeMethodSignature = new 
TransformMethodSignature(Modifier.PRIVATE, "void",
+                                                                               
      writeMethodName,
+                                                                               
      new String[]{STRING_CLASS_NAME},
+                                                                               
      null);
+        ct.addMethod(writeMethodSignature, String.format("throw new 
RuntimeException(\"write %s\");", baseName));
 
         ct.replaceWriteAccess(fieldName, writeMethodName);
     }
@@ -988,9 +959,7 @@
 
         ClassTransformation ct = 
createClassTransformation(EventHandlerTarget.class, logger);
 
-        OnEvent annotation = ct.getMethodAnnotation(
-                new TransformMethodSignature("handler"),
-                OnEvent.class);
+        OnEvent annotation = ct.getMethodAnnotation(new 
TransformMethodSignature("handler"), OnEvent.class);
 
         // Check that the attributes of the annotation match the expectation.
 
@@ -1016,9 +985,8 @@
         }
         catch (IllegalArgumentException ex)
         {
-            assertEquals(
-                    ex.getMessage(),
-                    "Class 
org.apache.tapestry.internal.transform.pages.ParentClass does not declare 
method 'public void foo()'.");
+            assertEquals(ex.getMessage(),
+                         "Class 
org.apache.tapestry.internal.transform.pages.ParentClass does not declare 
method 'public void foo()'.");
         }
 
         verify();
@@ -1056,6 +1024,125 @@
     }
 
     @Test
+    public void fields_in_prefixed_methods_are_transformed() throws Exception
+    {
+        Logger logger = mockLogger();
+        TransformMethodSignature sig = new 
TransformMethodSignature(Modifier.PUBLIC, "int", "getTargetValue", null,
+                                                                    null);
+        Runnable runnable = mockRunnable();
+
+        runnable.run();
+
+        replay();
+
+        InternalClassTransformation ct = 
createClassTransformation(MethodPrefixTarget.class, logger);
+
+        String name = ct.addInjectedField(Runnable.class, "runnable", 
runnable);
+
+        // Transform the field.
+
+        TransformMethodSignature reader = new 
TransformMethodSignature(Modifier.PRIVATE, "int", "read_target_value",
+                                                                       null, 
null);
+
+        ct.addMethod(reader, "return 66;");
+
+        ct.replaceReadAccess("_targetField", "read_target_value");
+
+        ct.prefixMethod(sig, name + ".run();");
+
+        ct.finish();
+
+        Object target = instantiate(MethodPrefixTarget.class, ct, null);
+
+        // 66 reflects the change to the field.
+
+        assertEquals(_access.get(target, "targetValue"), 66);
+
+        verify();
+    }
+
+    private Component instantiate(Class<?> expectedClass, 
InternalClassTransformation ct,
+                                  InternalComponentResources resources) throws 
Exception
+    {
+        CtClass targetObjectCtClass = findCtClass(expectedClass);
+
+        Class transformedClass = _classPool.toClass(targetObjectCtClass, 
_loader);
+
+        Instantiator ins = ct.createInstantiator(transformedClass);
+
+        return ins.newInstance(resources);
+    }
+
+    @Test
+    public void extend_existing_method_fields_are_transformed() throws 
Exception
+    {
+        Logger logger = mockLogger();
+        TransformMethodSignature sig = new 
TransformMethodSignature(Modifier.PUBLIC, "int", "getTargetValue", null,
+                                                                    null);
+        Runnable runnable = mockRunnable();
+
+        runnable.run();
+
+        replay();
+
+        InternalClassTransformation ct = 
createClassTransformation(MethodPrefixTarget.class, logger);
+
+        String name = ct.addInjectedField(Runnable.class, "runnable", 
runnable);
+
+        // Transform the field.
+
+        TransformMethodSignature reader = new 
TransformMethodSignature(Modifier.PRIVATE, "int", "read_target_value",
+                                                                       null, 
null);
+
+        ct.addMethod(reader, "return 66;");
+
+        ct.replaceReadAccess("_targetField", "read_target_value");
+
+        BodyBuilder builder = new BodyBuilder();
+        builder.begin();
+        builder.addln("%s.run();", name);
+        builder.addln("return $_ + 1;");
+        builder.end();
+
+        ct.extendExistingMethod(sig, builder.toString());
+
+        ct.finish();
+
+        Object target = instantiate(MethodPrefixTarget.class, ct, null);
+
+        // 66 reflects the change to the field, +1 reflects the extension of 
the method.
+
+        assertEquals(_access.get(target, "targetValue"), 67);
+
+        verify();
+    }
+
+    @Test
+    public void invalid_code() throws Exception
+    {
+        Logger logger = mockLogger();
+        TransformMethodSignature sig = new 
TransformMethodSignature(Modifier.PUBLIC, "int", "getParentField", null,
+                                                                    null);
+
+        replay();
+
+        InternalClassTransformation ct = 
createClassTransformation(ParentClass.class, logger);
+
+        try
+        {
+            ct.prefixMethod(sig, "return supercalafragalistic;");
+            unreachable();
+        }
+        catch (MethodCompileException ex)
+        {
+
+        }
+
+        verify();
+    }
+
+
+    @Test
     public void remove_field() throws Exception
     {
         Logger logger = mockLogger();
@@ -1064,8 +1151,8 @@
 
         CtClass targetObjectCtClass = findCtClass(FieldRemoval.class);
 
-        InternalClassTransformation ct = new 
InternalClassTransformationImpl(targetObjectCtClass,
-                                                                             
_contextClassLoader, logger, null);
+        InternalClassTransformation ct = new 
InternalClassTransformationImpl(targetObjectCtClass, _contextClassLoader,
+                                                                             
logger, null);
 
         ct.removeField("_fieldToRemove");
 
@@ -1097,10 +1184,11 @@
 
         TransformMethodSignature sig = sigs.get(0);
 
-        assertEquals(
-                ct.getMethodIdentifier(sig),
-                
"org.apache.tapestry.internal.transform.pages.MethodIdentifier.makeWaves(java.lang.String,
 int[]) (at MethodIdentifier.java:24)");
+        assertEquals(ct.getMethodIdentifier(sig),
+                     
"org.apache.tapestry.internal.transform.pages.MethodIdentifier.makeWaves(java.lang.String,
 int[]) (at MethodIdentifier.java:24)");
 
         verify();
     }
+
+
 }

Added: 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/MethodPrefixTarget.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/MethodPrefixTarget.java?rev=599949&view=auto
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/MethodPrefixTarget.java
 (added)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/MethodPrefixTarget.java
 Fri Nov 30 12:35:56 2007
@@ -0,0 +1,18 @@
+package org.apache.tapestry.internal.services;
+
+public class MethodPrefixTarget
+{
+    // If this is final, then the read is inlined, defeating the test.
+    private int _targetField = 42;
+
+    public int getTargetValue()
+    {
+        return _targetField;
+    }
+
+    // Again, necessary to defeat inlining of the value.
+    public void setTargetField(int value)
+    {
+        _targetField = value;
+    }
+}

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry/integration/app2/pages/TestPrefixMethod.tml
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry/integration/app2/pages/TestPrefixMethod.tml?rev=599949&r1=599948&r2=599949&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry/integration/app2/pages/TestPrefixMethod.tml
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry/integration/app2/pages/TestPrefixMethod.tml
 Fri Nov 30 12:35:56 2007
@@ -1,3 +1,5 @@
 <html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd";>
-  <span id="value">${value}</span>
+    <span id="value">${value}</span>
+    <span id="value2">${value2}</span>
+    <span id="value3">${value3}</span>
 </html>


Reply via email to