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 2011/05/02 19:37:38 UTC

svn commit: r1098683 - 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/testsubjects/

Author: hlship
Date: Mon May  2 17:37:38 2011
New Revision: 1098683

URL: http://svn.apache.org/viewvc?rev=1098683&view=rev
Log:
TAP5-853: Change PlasticField.createAccessors() to check for existing accessor methods and fail if they are present

Also, add test that checks that the generics signature propagates to the getter/setter methods

Added:
    tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/AccessorsAlreadyExistSubject.java
    tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/GenericCreateAccessorsSubject.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/plastic/PlasticField.java
    tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/FieldPropertyMethodCreation.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=1098683&r1=1098682&r2=1098683&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 May  2 17:37:38 2011
@@ -769,7 +769,9 @@ public class PlasticClassImpl extends Lo
 
             if (accessType != PropertyAccessType.WRITE_ONLY)
             {
-                introduceMethod(new MethodDescription(getTypeName(), "get" + capitalized, null)).changeImplementation(
+                String signature = node.signature == null ? null : "()" + node.signature;
+
+                introduceAccessorMethod(getTypeName(), "get" + capitalized, null, signature,
                         new InstructionBuilderCallback()
                         {
                             public void doBuild(InstructionBuilder builder)
@@ -781,21 +783,39 @@ public class PlasticClassImpl extends Lo
 
             if (accessType != PropertyAccessType.READ_ONLY)
             {
-                introduceMethod(new MethodDescription("void", "set" + capitalized, getTypeName()))
-                        .changeImplementation(new InstructionBuilderCallback()
-                        {
-                            public void doBuild(InstructionBuilder builder)
-                            {
-                                builder.loadThis().loadArgument(0);
-                                builder.putField(className, node.name, getTypeName());
-                                builder.returnResult();
-                            }
-                        });
+                String signature = node.signature == null ? null : "(" + node.signature + ")V";
+
+                introduceAccessorMethod("void", "set" + capitalized, new String[]
+                { getTypeName() }, node.signature, new InstructionBuilderCallback()
+                {
+                    public void doBuild(InstructionBuilder builder)
+                    {
+                        builder.loadThis().loadArgument(0);
+                        builder.putField(className, node.name, getTypeName());
+                        builder.returnResult();
+                    }
+                });
             }
 
             return this;
         }
 
+        private void introduceAccessorMethod(String returnType, String name, String[] parameterTypes, String signature,
+                InstructionBuilderCallback callback)
+        {
+            MethodDescription description = new MethodDescription(ACC_PUBLIC, returnType, name, parameterTypes,
+                    signature, null);
+
+            String desc = nameCache.toDesc(description);
+
+            if (methodBundle.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));
+
+            introduceMethod(description, callback);
+        }
+
         private void replaceFieldWriteAccess(String conduitFieldName)
         {
             String setAccessName = makeUnique(methodNames, "set_" + node.name);

Modified: tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticField.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticField.java?rev=1098683&r1=1098682&r2=1098683&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticField.java (original)
+++ tapestry/tapestry5/trunk/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticField.java Mon May  2 17:37:38 2011
@@ -126,25 +126,28 @@ public interface PlasticField extends An
      * Creates access to the field, using the default property name derived from the name of the field.
      * The default property name is the same as the name of the field, but with any leading or trailing underscore
      * characters removed (a common convention among some programmers). Also, strips leading "m_" from the field name
-     * (another
-     * common convention).
+     * (another common convention).
      * 
      * @param accessType
      *            which methods to create
      * @return the field for further manipulation
+     * @throws IllegalArgumentException
+     *             if an accessor method to be created already exists (possibly inherited from a base class)
      */
     PlasticField createAccessors(PropertyAccessType accessType);
 
     /**
      * Creates accessors, possibly replacing existing methods (or overriding methods from a super class).
      * The method names consist of the property name, with its first character converted to upper-case, prefixed
-     * with "get" or "set".
+     * with "get" or "set". The accessor methods must not already exist.
      * 
      * @param accessType
      *            which methods to create
      * @param propertyName
      *            the name of the property (from which the names of the methods are generated)
      * @return the field for further manipulation
+     * @throws IllegalArgumentException
+     *             if an accessor method to be created already exists (possibly inherited from a base class)
      */
     PlasticField createAccessors(PropertyAccessType accessType, String propertyName);
 

Added: tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/AccessorsAlreadyExistSubject.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/AccessorsAlreadyExistSubject.java?rev=1098683&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/AccessorsAlreadyExistSubject.java (added)
+++ tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/AccessorsAlreadyExistSubject.java Mon May  2 17:37:38 2011
@@ -0,0 +1,19 @@
+package org.apache.tapestry5.plastic;
+
+import testannotations.Property;
+
+public class AccessorsAlreadyExistSubject
+{
+    @Property
+    private String value;
+
+    public String getValue()
+    {
+        return value;
+    }
+
+    public void setValue(String value)
+    {
+        this.value = value;
+    }
+}

Modified: tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/FieldPropertyMethodCreation.groovy
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/FieldPropertyMethodCreation.groovy?rev=1098683&r1=1098682&r2=1098683&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/FieldPropertyMethodCreation.groovy (original)
+++ tapestry/tapestry5/trunk/plastic/src/test/groovy/org/apache/tapestry5/plastic/FieldPropertyMethodCreation.groovy Mon May  2 17:37:38 2011
@@ -14,23 +14,29 @@
 
 package org.apache.tapestry5.plastic
 
-import org.apache.tapestry5.plastic.PlasticManager;
-import org.apache.tapestry5.plastic.PropertyAccessType;
+import java.util.concurrent.atomic.AtomicReference
 
-import spock.lang.Specification;
-import testannotations.Property;
+import spock.lang.Specification
+import testannotations.Property
+import testsubjects.CreateAccessorsSubject
+import testsubjects.GenericCreateAccessorsSubject
 
 class FieldPropertyMethodCreation extends Specification
 {
-    def "create accessors for fields"() {
-        setup:
-
+    def withAccessors(Class subject, PropertyAccessType accessType) {
         def mgr = new PlasticManager()
-        def pc = mgr.getPlasticClass ("testsubjects.CreateAccessorsSubject")
+        def pc = mgr.getPlasticClass (subject.name)
 
-        pc.getFieldsWithAnnotation(Property.class).each { f -> f.createAccessors(PropertyAccessType.READ_WRITE) }
+        pc.getFieldsWithAnnotation(Property.class).each { f ->
+            f.createAccessors(accessType)
+        }
 
         def o = pc.createInstantiator().newInstance()
+    }
+
+    def "create accessors for fields"() {
+
+        def o = withAccessors(CreateAccessorsSubject.class, PropertyAccessType.READ_WRITE)
 
         when:
 
@@ -62,4 +68,45 @@ class FieldPropertyMethodCreation extend
         then: "Setting primitive property reflected in original field"
         assert o.m_count == o.count
     }
+
+    def "create accessors for generic fields"() {
+
+        def o = withAccessors(GenericCreateAccessorsSubject.class, PropertyAccessType.READ_WRITE)
+
+        def ref = new AtomicReference<String>("Plastic")
+
+        o.ref = ref
+
+        expect:
+
+        assert o.ref == ref
+        assert o.refValue == "Plastic"
+
+        o.class.getMethod("getRef").signature == "()Ljava/util/concurrent/atomic/AtomicReference<Ljava/lang/String;>;"
+        o.class.getMethod("setRef", AtomicReference.class).signature == "Ljava/util/concurrent/atomic/AtomicReference<Ljava/lang/String;>;"
+    }
+
+    def "create getter that already exists"() {
+        when:
+
+        withAccessors(AccessorsAlreadyExistSubject.class, PropertyAccessType.READ_ONLY)
+
+        then:
+
+        def e = thrown(IllegalArgumentException)
+
+        assert e.message == "Unable to create new accessor method public java.lang.String getValue() on class org.apache.tapestry5.plastic.AccessorsAlreadyExistSubject as the method is already implemented."
+    }
+
+    def "create setter that already exists"() {
+        when:
+
+        withAccessors(AccessorsAlreadyExistSubject.class, PropertyAccessType.WRITE_ONLY)
+
+        then:
+
+        def e = thrown(IllegalArgumentException)
+
+        assert e.message == "Unable to create new accessor method public void setValue(java.lang.String) on class org.apache.tapestry5.plastic.AccessorsAlreadyExistSubject as the method is already implemented."
+    }
 }

Added: tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/GenericCreateAccessorsSubject.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/GenericCreateAccessorsSubject.java?rev=1098683&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/GenericCreateAccessorsSubject.java (added)
+++ tapestry/tapestry5/trunk/plastic/src/test/java/testsubjects/GenericCreateAccessorsSubject.java Mon May  2 17:37:38 2011
@@ -0,0 +1,16 @@
+package testsubjects;
+
+import java.util.concurrent.atomic.AtomicReference;
+
+import testannotations.Property;
+
+public class GenericCreateAccessorsSubject
+{
+    @Property
+    private AtomicReference<String> m_ref;
+
+    public String getRefValue()
+    {
+        return m_ref.get();
+    }
+}