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 2008/05/22 18:57:46 UTC

svn commit: r659159 - in /tapestry/tapestry5/trunk: tapestry-annotations/src/main/java/org/apache/tapestry5/beaneditor/ tapestry-core/src/main/java/org/apache/tapestry5/internal/ tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ tapes...

Author: hlship
Date: Thu May 22 09:57:45 2008
New Revision: 659159

URL: http://svn.apache.org/viewvc?rev=659159&view=rev
Log:
TAPESTRY-2425: Tapestry annotations such as @Validate, @DataType, etc. should be applicable to fields as well as accessor methods

Added:
    tapestry/tapestry5/trunk/tapestry-annotations/src/main/java/org/apache/tapestry5/beaneditor/ReorderProperties.java
Removed:
    tapestry/tapestry5/trunk/tapestry-annotations/src/main/java/org/apache/tapestry5/beaneditor/OrderAfter.java
    tapestry/tapestry5/trunk/tapestry-annotations/src/main/java/org/apache/tapestry5/beaneditor/OrderBefore.java
Modified:
    tapestry/tapestry5/trunk/tapestry-annotations/src/main/java/org/apache/tapestry5/beaneditor/DataType.java
    tapestry/tapestry5/trunk/tapestry-annotations/src/main/java/org/apache/tapestry5/beaneditor/NonVisual.java
    tapestry/tapestry5/trunk/tapestry-annotations/src/main/java/org/apache/tapestry5/beaneditor/Validate.java
    tapestry/tapestry5/trunk/tapestry-annotations/src/main/java/org/apache/tapestry5/beaneditor/Width.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/BeanModelSourceImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/BeanModelSource.java
    tapestry/tapestry5/trunk/tapestry-core/src/site/apt/upgrade.apt
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/data/RegistrationData.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/data/SimpleTrack.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/PropertyOrderBean.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/TapestryInternalUtilsTest.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/bindings/PropBindingFactoryTest.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/bindings/TargetBean.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/BeanModelSourceImplTest.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/StoogeBean.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAdapter.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImplTest.java

Modified: tapestry/tapestry5/trunk/tapestry-annotations/src/main/java/org/apache/tapestry5/beaneditor/DataType.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-annotations/src/main/java/org/apache/tapestry5/beaneditor/DataType.java?rev=659159&r1=659158&r2=659159&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-annotations/src/main/java/org/apache/tapestry5/beaneditor/DataType.java (original)
+++ tapestry/tapestry5/trunk/tapestry-annotations/src/main/java/org/apache/tapestry5/beaneditor/DataType.java Thu May 22 09:57:45 2008
@@ -1,4 +1,4 @@
-// Copyright 2007 The Apache Software Foundation
+// Copyright 2007, 2008 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.
@@ -18,10 +18,10 @@
 
 /**
  * Used to explicitly set the data type used to select an editor (or display) block.  Normally, the data type is
- * determined from the type of the property (for example, property type java.lang.String would map to data type
- * "text").
+ * determined from the type of the property (for example, property type java.lang.String would map to data type "text").
+ * This annotation may be attached to a getter or setter method, or the matching field.
  */
-@Target(ElementType.METHOD)
+@Target({ ElementType.FIELD, ElementType.METHOD })
 @Retention(RetentionPolicy.RUNTIME)
 @Documented
 public @interface DataType

Modified: tapestry/tapestry5/trunk/tapestry-annotations/src/main/java/org/apache/tapestry5/beaneditor/NonVisual.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-annotations/src/main/java/org/apache/tapestry5/beaneditor/NonVisual.java?rev=659159&r1=659158&r2=659159&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-annotations/src/main/java/org/apache/tapestry5/beaneditor/NonVisual.java (original)
+++ tapestry/tapestry5/trunk/tapestry-annotations/src/main/java/org/apache/tapestry5/beaneditor/NonVisual.java Thu May 22 09:57:45 2008
@@ -1,4 +1,4 @@
-// Copyright 2007 The Apache Software Foundation
+// Copyright 2007, 2008 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.
@@ -15,16 +15,16 @@
 package org.apache.tapestry5.beaneditor;
 
 import java.lang.annotation.Documented;
-import static java.lang.annotation.ElementType.METHOD;
+import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import static java.lang.annotation.RetentionPolicy.RUNTIME;
 import java.lang.annotation.Target;
 
 /**
  * Marker annotation for properties which are non-visual, and so should not appear (by default) inside a {@link
- * BeanModel}. The annotation may be placed on either the getter or the setter method.
+ * BeanModel}. The annotation may be placed on either the getter or the setter method or on the field.
  */
-@Target(METHOD)
+@Target({ ElementType.FIELD, ElementType.METHOD })
 @Retention(RUNTIME)
 @Documented
 public @interface NonVisual

Added: tapestry/tapestry5/trunk/tapestry-annotations/src/main/java/org/apache/tapestry5/beaneditor/ReorderProperties.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-annotations/src/main/java/org/apache/tapestry5/beaneditor/ReorderProperties.java?rev=659159&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-annotations/src/main/java/org/apache/tapestry5/beaneditor/ReorderProperties.java (added)
+++ tapestry/tapestry5/trunk/tapestry-annotations/src/main/java/org/apache/tapestry5/beaneditor/ReorderProperties.java Thu May 22 09:57:45 2008
@@ -0,0 +1,33 @@
+// Copyright 2008 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.tapestry5.beaneditor;
+
+import java.lang.annotation.*;
+
+
+/**
+ * An annotation that may be placed on a JavaBean to re-order the properties.
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface ReorderProperties
+{
+    /**
+     * A comma-separated list of property names.  Properties will be re-ordered as specified, with any unmentioned
+     * property names ordered to the end of the list.
+     */
+    String value();
+}

Modified: tapestry/tapestry5/trunk/tapestry-annotations/src/main/java/org/apache/tapestry5/beaneditor/Validate.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-annotations/src/main/java/org/apache/tapestry5/beaneditor/Validate.java?rev=659159&r1=659158&r2=659159&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-annotations/src/main/java/org/apache/tapestry5/beaneditor/Validate.java (original)
+++ tapestry/tapestry5/trunk/tapestry-annotations/src/main/java/org/apache/tapestry5/beaneditor/Validate.java Thu May 22 09:57:45 2008
@@ -1,4 +1,4 @@
-// Copyright 2007 The Apache Software Foundation
+// Copyright 2007, 2008 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.
@@ -15,7 +15,7 @@
 package org.apache.tapestry5.beaneditor;
 
 import java.lang.annotation.Documented;
-import static java.lang.annotation.ElementType.METHOD;
+import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import static java.lang.annotation.RetentionPolicy.RUNTIME;
 import java.lang.annotation.Target;
@@ -25,8 +25,10 @@
  * value is a comma separated list of <em>validation constraints</em>, each one identifying a validator type (such as
  * "required", "minlength") and optionally, a constraint value. Most validators need a constraint value, which is
  * separated from the type by an equals size (i.e., "maxlength=30").
+ * <p/>
+ * May be placed on an getter or setter method, or on the matching field.
  */
-@Target(METHOD)
+@Target({ ElementType.FIELD, ElementType.METHOD })
 @Retention(RUNTIME)
 @Documented
 public @interface Validate

Modified: tapestry/tapestry5/trunk/tapestry-annotations/src/main/java/org/apache/tapestry5/beaneditor/Width.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-annotations/src/main/java/org/apache/tapestry5/beaneditor/Width.java?rev=659159&r1=659158&r2=659159&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-annotations/src/main/java/org/apache/tapestry5/beaneditor/Width.java (original)
+++ tapestry/tapestry5/trunk/tapestry-annotations/src/main/java/org/apache/tapestry5/beaneditor/Width.java Thu May 22 09:57:45 2008
@@ -1,4 +1,4 @@
-// Copyright 2007 The Apache Software Foundation
+// Copyright 2007, 2008 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.
@@ -14,18 +14,17 @@
 
 package org.apache.tapestry5.beaneditor;
 
-import java.lang.annotation.Documented;
-import static java.lang.annotation.ElementType.METHOD;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
+import java.lang.annotation.*;
 
 /**
  * Defines the desired width of the field used to edit the property.  Note that width (generally equivalent to the size
  * attribute of an HTML &lt;input&gt; element) is only used for presentation; validation must be used to actually
  * enforce a maximum input length.
+ * <p/>
+ * <p/>
+ * May be placed on an getter or setter method, or on the matching field.
  */
-@Target(METHOD)
+@Target({ ElementType.FIELD, ElementType.METHOD })
 @Retention(RetentionPolicy.RUNTIME)
 @Documented
 public @interface Width

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java?rev=659159&r1=659158&r2=659159&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java Thu May 22 09:57:45 2008
@@ -18,24 +18,14 @@
 import org.apache.commons.codec.net.URLCodec;
 import org.apache.tapestry5.OptionModel;
 import org.apache.tapestry5.SelectModel;
-import org.apache.tapestry5.beaneditor.OrderAfter;
-import org.apache.tapestry5.beaneditor.OrderBefore;
-import org.apache.tapestry5.ioc.Location;
 import org.apache.tapestry5.ioc.Messages;
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
 import static org.apache.tapestry5.ioc.internal.util.CollectionFactory.newList;
 import org.apache.tapestry5.ioc.internal.util.Defense;
 import static org.apache.tapestry5.ioc.internal.util.Defense.notNull;
 import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-import org.apache.tapestry5.ioc.internal.util.Orderer;
-import org.apache.tapestry5.ioc.services.ClassFactory;
-import org.apache.tapestry5.ioc.services.ClassPropertyAdapter;
-import org.apache.tapestry5.ioc.services.PropertyAdapter;
-import org.slf4j.Logger;
 
-import java.lang.reflect.Method;
 import java.util.BitSet;
-import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.regex.Pattern;
@@ -342,124 +332,6 @@
         return InternalUtils.join(classes, " ");
     }
 
-    private static class PropertyOrder implements Comparable<PropertyOrder>
-    {
-        final String propertyName;
-
-        final int classDepth;
-
-        final int sortKey;
-
-        public PropertyOrder(final String propertyName, int classDepth, int sortKey)
-        {
-            this.propertyName = propertyName;
-            this.classDepth = classDepth;
-            this.sortKey = sortKey;
-        }
-
-        public int compareTo(PropertyOrder o)
-        {
-            int result = classDepth - o.classDepth;
-
-            if (result == 0) result = sortKey - o.sortKey;
-
-            if (result == 0) result = propertyName.compareTo(o.propertyName);
-
-            return result;
-        }
-    }
-
-    /**
-     * Sorts the property names into presentation order. Filters out any properties that have an explicit {@link
-     * OrderBefore}, leaving the remainder. Estimates each propertie's position based on the relative position of the
-     * property's getter. The code assumes that all methods are readable (have a getter method).
-     *
-     * @param classAdapter  defines the bean that contains the properties
-     * @param classFactory  used to access method line number information
-     * @param propertyNames the initial set of property names
-     * @return propertyNames filtered and sorted
-     */
-    public static List<String> orderProperties(Logger logger, ClassPropertyAdapter classAdapter,
-                                               ClassFactory classFactory, List<String> propertyNames)
-    {
-
-        // Property name to a list of constraints.
-        Map<String, List<String>> constraints = CollectionFactory.newMap();
-
-        List<PropertyOrder> properties = newList();
-
-        for (String name : propertyNames)
-        {
-
-            PropertyAdapter pa = classAdapter.getPropertyAdapter(name);
-            List<String> propertyConstraints = CollectionFactory.newList();
-
-            OrderBefore beforeAnnotation = pa.getAnnotation(OrderBefore.class);
-
-            if (beforeAnnotation != null) propertyConstraints.add("before:" + beforeAnnotation.value());
-
-            OrderAfter afterAnnotation = pa.getAnnotation(OrderAfter.class);
-
-            if (afterAnnotation != null) propertyConstraints.add("after:" + afterAnnotation.value());
-
-            if (!propertyConstraints.isEmpty()) constraints.put(name, propertyConstraints);
-
-            Method readMethod = pa.getReadMethod();
-
-            Location location = classFactory.getMethodLocation(readMethod);
-
-            properties.add(new PropertyOrder(name, computeDepth(readMethod), location.getLine()));
-        }
-
-        Collections.sort(properties);
-
-        Orderer<String> orderer = new Orderer<String>(logger);
-        String prev = null;
-
-        for (PropertyOrder po : properties)
-        {
-            String name = po.propertyName;
-
-            List<String> propertyConstraints = constraints.get(name);
-
-            if (propertyConstraints != null)
-            {
-
-                String[] asArray = propertyConstraints.toArray(new String[propertyConstraints
-                        .size()]);
-
-                orderer.add(name, name, asArray);
-
-                prev = name;
-
-                continue;
-            }
-
-            if (prev == null) orderer.add(name, name);
-            else orderer.add(name, name, "after:" + prev);
-
-            prev = name;
-        }
-
-        return orderer.getOrdered();
-
-    }
-
-    private static int computeDepth(Method method)
-    {
-        int depth = 0;
-        Class c = method.getDeclaringClass();
-
-        // When the method originates in an interface, the parent may be null, not Object.
-
-        while (c != null && c != Object.class)
-        {
-            depth++;
-            c = c.getSuperclass();
-        }
-
-        return depth;
-    }
 
     /**
      * Converts an enum to a label string, allowing for overrides from a message catalog.

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/BeanModelSourceImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/BeanModelSourceImpl.java?rev=659159&r1=659158&r2=659159&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/BeanModelSourceImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/BeanModelSourceImpl.java Thu May 22 09:57:45 2008
@@ -17,8 +17,10 @@
 import org.apache.tapestry5.ComponentResources;
 import org.apache.tapestry5.beaneditor.BeanModel;
 import org.apache.tapestry5.beaneditor.NonVisual;
-import org.apache.tapestry5.internal.TapestryInternalUtils;
+import org.apache.tapestry5.beaneditor.ReorderProperties;
 import org.apache.tapestry5.internal.beaneditor.BeanModelImpl;
+import org.apache.tapestry5.internal.beaneditor.BeanModelUtils;
+import org.apache.tapestry5.ioc.Location;
 import org.apache.tapestry5.ioc.LoggerSource;
 import org.apache.tapestry5.ioc.Messages;
 import org.apache.tapestry5.ioc.ObjectLocator;
@@ -31,8 +33,9 @@
 import org.apache.tapestry5.services.DataTypeAnalyzer;
 import org.apache.tapestry5.services.PropertyConduitSource;
 
+import java.lang.reflect.Method;
+import java.util.Collections;
 import java.util.List;
-import java.util.Map;
 
 public class BeanModelSourceImpl implements BeanModelSource
 {
@@ -50,6 +53,81 @@
 
     private final ObjectLocator locator;
 
+
+    private static class PropertyOrder implements Comparable<PropertyOrder>
+    {
+        final String propertyName;
+
+        final int classDepth;
+
+        final int sortKey;
+
+        public PropertyOrder(final String propertyName, int classDepth, int sortKey)
+        {
+            this.propertyName = propertyName;
+            this.classDepth = classDepth;
+            this.sortKey = sortKey;
+        }
+
+        public int compareTo(PropertyOrder o)
+        {
+            int result = classDepth - o.classDepth;
+
+            if (result == 0) result = sortKey - o.sortKey;
+
+            if (result == 0) result = propertyName.compareTo(o.propertyName);
+
+            return result;
+        }
+    }
+
+    /**
+     * @param classAdapter  defines the bean that contains the properties
+     * @param propertyNames the initial set of property names, which will be rebuilt in the correct order
+     */
+    private void orderProperties(ClassPropertyAdapter classAdapter, List<String> propertyNames)
+    {
+        List<PropertyOrder> properties = CollectionFactory.newList();
+
+        for (String name : propertyNames)
+        {
+            PropertyAdapter pa = classAdapter.getPropertyAdapter(name);
+            List<String> propertyConstraints = CollectionFactory.newList();
+
+            Method readMethod = pa.getReadMethod();
+
+            Location location = classFactory.getMethodLocation(readMethod);
+
+            properties.add(new PropertyOrder(name, computeDepth(readMethod), location.getLine()));
+        }
+
+        Collections.sort(properties);
+
+        propertyNames.clear();
+
+        for (PropertyOrder po : properties)
+        {
+            propertyNames.add(po.propertyName);
+        }
+
+    }
+
+    private static int computeDepth(Method method)
+    {
+        int depth = 0;
+        Class c = method.getDeclaringClass();
+
+        // When the method originates in an interface, the parent may be null, not Object.
+
+        while (c != null && c != Object.class)
+        {
+            depth++;
+            c = c.getSuperclass();
+        }
+
+        return depth;
+    }
+
     public BeanModelSourceImpl(LoggerSource loggerSource, TypeCoercer typeCoercer, PropertyAccess propertyAccess,
                                PropertyConduitSource propertyConduitSource, @ComponentLayer ClassFactory classFactory,
                                @Primary DataTypeAnalyzer dataTypeAnalyzer, ObjectLocator locator)
@@ -72,12 +150,8 @@
 
         ClassPropertyAdapter adapter = propertyAccess.getAdapter(beanClass);
 
-        final BeanModel<T> model = new BeanModelImpl<T>(beanClass, propertyConduitSource, typeCoercer, messages,
-                                                        locator);
-
-        List<String> propertyNames = CollectionFactory.newList();
-
-        Map<String, Runnable> worksheet = CollectionFactory.newMap();
+        BeanModel<T> model = new BeanModelImpl<T>(beanClass, propertyConduitSource, typeCoercer, messages,
+                                                  locator);
 
         for (final String propertyName : adapter.getPropertyNames())
         {
@@ -95,38 +169,28 @@
 
             if (dataType == null) continue;
 
-            propertyNames.add(propertyName);
-
-            // We need to defer execution of this; we want to add them in proper order, not
-            // alphabetical order.
+            model.add(propertyName).dataType(dataType);
+        }
 
-            Runnable worker = new Runnable()
-            {
-                public void run()
-                {
-                    model.add(propertyName).dataType(dataType);
-                }
-            };
+        // First, order the properties based on the location of the getter method
+        // within the class.
 
-            worksheet.put(propertyName, worker);
-        }
+        List<String> propertyNames = model.getPropertyNames();
 
-        // Determine the correct order to add the properties.
+        orderProperties(adapter, propertyNames);
 
-        List<String> orderedNames = TapestryInternalUtils.orderProperties(loggerSource
-                .getLogger(beanClass), adapter, classFactory, propertyNames);
+        model.reorder(propertyNames.toArray(new String[propertyNames.size()]));
 
-        for (String propertyName : orderedNames)
-        {
-            Runnable r = worksheet.get(propertyName);
+        // Next, check for an annotation with specific ordering information.
 
-            // This actually adds the property to the model, but we're doing it
-            // in orderedNames order, not propertyNames order (which is alphabetical).
-            // The default ordering comes from method ordering within the class.
+        ReorderProperties reorderAnnotation = beanClass.getAnnotation(ReorderProperties.class);
 
-            r.run();
+        if (reorderAnnotation != null)
+        {
+            BeanModelUtils.reorder(model, reorderAnnotation.value());
         }
 
+
         return model;
     }
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/BeanModelSource.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/BeanModelSource.java?rev=659159&r1=659158&r2=659159&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/BeanModelSource.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/BeanModelSource.java Thu May 22 09:57:45 2008
@@ -16,11 +16,10 @@
 
 import org.apache.tapestry5.ComponentResources;
 import org.apache.tapestry5.beaneditor.BeanModel;
-import org.apache.tapestry5.beaneditor.OrderBefore;
 
 /**
- * Used by a component to create a default {@link BeanModel} for a particular bean class. Also provides support to the
- * model by generating validation information for individual fields.
+ * Used by a component to create a default {@link org.apache.tapestry5.beaneditor.BeanModel} for a particular bean
+ * class. Also provides support to the model by generating validation information for individual fields.
  * <p/>
  * BeanModels are the basis for the {@link org.apache.tapestry5.corelib.components.BeanEditor} and {@link
  * org.apache.tapestry5.corelib.components.Grid} comopnents.
@@ -31,9 +30,10 @@
 {
     /**
      * Creates a new model used for editing the indicated bean class. The model will represent all read/write properties
-     * of the bean. The order of the properties is defined by the {@link OrderBefore} annotation on the getter or setter
-     * methods. The labels for the properties are derived from the property names, but if the component's message
-     * catalog has keys of the form <code>propertyName-label</code>, then those will be used instead.
+     * of the bean. The order of properties is determined from the order of the getter methods in the code, and can be
+     * overridden with the {@link org.apache.tapestry5.beaneditor.ReorderProperties} annotation. The labels for the
+     * properties are derived from the property names, but if the component's message catalog has keys of the form
+     * <code>propertyName-label</code>, then those will be used instead.
      * <p/>
      * Models are <em>mutable</em>, so they are not cached, a fresh instance is created each time.
      *

Modified: tapestry/tapestry5/trunk/tapestry-core/src/site/apt/upgrade.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/site/apt/upgrade.apt?rev=659159&r1=659158&r2=659159&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/site/apt/upgrade.apt (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/site/apt/upgrade.apt Thu May 22 09:57:45 2008
@@ -14,6 +14,13 @@
 
 Release 5.0.12
 
+* ReorderProperties annotation
+
+  A new annotation,
+  {{{../apidocs/org/apache/tapestry5/beaneditor/ReorderProperties.html}ReorderProperties}}
+  (which is placed on a type) has replaced the OrderAfter and OrderBefore annotations
+  (which were placed on accessor methods).
+
 * {{{https://issues.apache.org/jira/browse/TAPESTRY-2421}TAPESTRY-2421}}
 
   To enable deployment compatibility between Tapestry 4 and Tapestry 5, a

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/data/RegistrationData.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/data/RegistrationData.java?rev=659159&r1=659158&r2=659159&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/data/RegistrationData.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/data/RegistrationData.java Thu May 22 09:57:45 2008
@@ -14,8 +14,12 @@
 
 package org.apache.tapestry5.integration.app1.data;
 
-import org.apache.tapestry5.beaneditor.*;
+import org.apache.tapestry5.beaneditor.DataType;
+import org.apache.tapestry5.beaneditor.ReorderProperties;
+import org.apache.tapestry5.beaneditor.Validate;
+import org.apache.tapestry5.beaneditor.Width;
 
+@ReorderProperties("firstname,lastname,birthyear,sex")
 public class RegistrationData
 {
     private String lastName;
@@ -32,7 +36,6 @@
 
     private String notes;
 
-    @OrderAfter("lastName")
     @Validate("min=1900,max=2007")
     @Width(4)
     public int getBirthYear()
@@ -40,13 +43,11 @@
         return birthYear;
     }
 
-    @OrderAfter("lastname,birthyear")
     public Sex getSex()
     {
         return sex;
     }
 
-    @OrderBefore("lastname")
     public String getFirstName()
     {
         return firstName;

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/data/SimpleTrack.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/data/SimpleTrack.java?rev=659159&r1=659158&r2=659159&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/data/SimpleTrack.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/data/SimpleTrack.java Thu May 22 09:57:45 2008
@@ -1,4 +1,4 @@
-// Copyright 2007 The Apache Software Foundation
+// Copyright 2007, 2008 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.
@@ -14,14 +14,13 @@
 
 package org.apache.tapestry5.integration.app1.data;
 
-import org.apache.tapestry5.beaneditor.OrderBefore;
+import org.apache.tapestry5.beaneditor.ReorderProperties;
 
+@ReorderProperties("title,album")
 public interface SimpleTrack
 {
-    @OrderBefore("album")
     String getTitle();
 
-    @OrderBefore("rating")
     String getAlbum();
 
     int getRating();

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/PropertyOrderBean.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/PropertyOrderBean.java?rev=659159&r1=659158&r2=659159&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/PropertyOrderBean.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/PropertyOrderBean.java Thu May 22 09:57:45 2008
@@ -1,4 +1,4 @@
-// Copyright 2007 The Apache Software Foundation
+// Copyright 2007, 2008 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.
@@ -14,8 +14,9 @@
 
 package org.apache.tapestry5.internal;
 
-import org.apache.tapestry5.beaneditor.OrderBefore;
+import org.apache.tapestry5.beaneditor.ReorderProperties;
 
+@ReorderProperties("third")
 public class PropertyOrderBean
 {
     private String first;
@@ -34,7 +35,6 @@
         return second;
     }
 
-    @OrderBefore("first")
     public String getThird()
     {
         return third;

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/TapestryInternalUtilsTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/TapestryInternalUtilsTest.java?rev=659159&r1=659158&r2=659159&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/TapestryInternalUtilsTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/TapestryInternalUtilsTest.java Thu May 22 09:57:45 2008
@@ -21,10 +21,10 @@
 import org.apache.tapestry5.ioc.Messages;
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
 import org.apache.tapestry5.ioc.services.ClassFactory;
-import org.apache.tapestry5.ioc.services.ClassPropertyAdapter;
 import org.apache.tapestry5.ioc.services.PropertyAccess;
 import org.apache.tapestry5.ioc.services.TypeCoercer;
 import org.apache.tapestry5.runtime.ComponentResourcesAware;
+import org.apache.tapestry5.services.BeanModelSource;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.DataProvider;
@@ -39,11 +39,14 @@
 
     private PropertyAccess access;
 
+    private BeanModelSource beanModelSource;
+
     @BeforeClass
     public void setup()
     {
         classFactory = getService("ClassFactory", ClassFactory.class);
         access = getService("PropertyAccess", PropertyAccess.class);
+        beanModelSource = getService(BeanModelSource.class);
     }
 
     @AfterClass
@@ -51,6 +54,7 @@
     {
         access = null;
         classFactory = null;
+        beanModelSource = null;
     }
 
 
@@ -295,52 +299,6 @@
     }
 
     @Test
-    public void property_order_basic()
-    {
-        ClassPropertyAdapter adapter = access.getAdapter(DataBean.class);
-
-        List<String> names = adapter.getPropertyNames();
-
-        names.remove("class");
-
-        List<String> sorted = TapestryInternalUtils.orderProperties(null, adapter, classFactory, names);
-
-        assertEquals(sorted, Arrays.asList("firstName", "lastName", "age"));
-    }
-
-    @Test
-    public void property_order_on_subclass()
-    {
-        ClassPropertyAdapter adapter = access.getAdapter(DataBeanSubclass.class);
-
-        List<String> names = adapter.getPropertyNames();
-
-        names.remove("class");
-
-        List<String> sorted = TapestryInternalUtils.orderProperties(null, adapter, classFactory, names);
-
-        // Subclass properties listed after superclass properties, as desired.
-
-        assertEquals(sorted, Arrays.asList("firstName", "lastName", "age", "street", "city", "state", "zip"));
-    }
-
-    @Test
-    public void properties_with_order_annotation_filtered()
-    {
-        ClassPropertyAdapter adapter = access.getAdapter(PropertyOrderBean.class);
-
-        List<String> names = adapter.getPropertyNames();
-
-        names.remove("class");
-
-        List<String> sorted = TapestryInternalUtils.orderProperties(null, adapter, classFactory, names);
-
-        // Property third has an explicit @OrderBefore
-
-        assertEquals(sorted, Arrays.asList("third", "first", "second"));
-    }
-
-    @Test
     public void null_equals_null()
     {
         assertTrue(TapestryInternalUtils.isEqual(null, null));

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/bindings/PropBindingFactoryTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/bindings/PropBindingFactoryTest.java?rev=659159&r1=659158&r2=659159&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/bindings/PropBindingFactoryTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/bindings/PropBindingFactoryTest.java Thu May 22 09:57:45 2008
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007 The Apache Software Foundation
+// Copyright 2006, 2007, 2008 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.
@@ -17,8 +17,7 @@
 import org.apache.tapestry5.Binding;
 import org.apache.tapestry5.ComponentResources;
 import org.apache.tapestry5.annotations.BeforeRenderBody;
-import org.apache.tapestry5.beaneditor.OrderAfter;
-import org.apache.tapestry5.beaneditor.OrderBefore;
+import org.apache.tapestry5.beaneditor.Validate;
 import org.apache.tapestry5.internal.test.InternalBaseTestCase;
 import org.apache.tapestry5.internal.util.IntegerRange;
 import org.apache.tapestry5.ioc.Location;
@@ -95,7 +94,7 @@
 
         Binding binding = factory.newBinding("test binding", resources, null, "readOnly", l);
 
-        assertEquals(binding.getAnnotation(OrderBefore.class).value(), "writeOnly");
+        assertEquals(binding.getAnnotation(Validate.class).value(), "readonly");
 
         verify();
     }
@@ -111,7 +110,7 @@
 
         Binding binding = factory.newBinding("test binding", resources, null, "writeOnly", l);
 
-        assertEquals(binding.getAnnotation(OrderAfter.class).value(), "foobar");
+        assertEquals(binding.getAnnotation(Validate.class).value(), "writeonly");
 
         verify();
     }
@@ -127,7 +126,7 @@
 
         Binding binding = factory.newBinding("test binding", resources, null, "intValue", l);
 
-        assertNull(binding.getAnnotation(OrderBefore.class));
+        assertNull(binding.getAnnotation(Validate.class));
 
         verify();
     }
@@ -164,7 +163,7 @@
 
         Binding binding = factory.newBinding("test binding", resources, null, "objectValue", l);
 
-        assertEquals(binding.getAnnotation(OrderAfter.class).value(), "readOnly");
+        assertEquals(binding.getAnnotation(Validate.class).value(), "getObjectValue");
 
         verify();
     }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/bindings/TargetBean.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/bindings/TargetBean.java?rev=659159&r1=659158&r2=659159&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/bindings/TargetBean.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/bindings/TargetBean.java Thu May 22 09:57:45 2008
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007 The Apache Software Foundation
+// Copyright 2006, 2007, 2008 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.
@@ -15,9 +15,10 @@
 package org.apache.tapestry5.internal.bindings;
 
 import org.apache.tapestry5.annotations.BeforeRenderBody;
-import org.apache.tapestry5.beaneditor.OrderAfter;
-import org.apache.tapestry5.beaneditor.OrderBefore;
+import org.apache.tapestry5.beaneditor.ReorderProperties;
+import org.apache.tapestry5.beaneditor.Validate;
 
+@ReorderProperties("readonly,foobar,writeonly,objectvalue")
 public class TargetBean extends DefaultComponent
 {
     private String objectValue;
@@ -54,25 +55,25 @@
         this.intValue = intValue;
     }
 
-    @OrderAfter("readOnly")
+    @Validate("getObjectValue")
     public String getObjectValue()
     {
         return objectValue;
     }
 
-    @OrderAfter("writeOnly")
+    @Validate("setObjectValue")
     public void setObjectValue(String objectValue)
     {
         this.objectValue = objectValue;
     }
 
-    @OrderAfter("foobar")
+    @Validate("writeonly")
     public void setWriteOnly(String value)
     {
         writeOnly = value;
     }
 
-    @OrderBefore("writeOnly")
+    @Validate("readonly")
     public String getReadOnly()
     {
         return "ReadOnly";

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/BeanModelSourceImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/BeanModelSourceImplTest.java?rev=659159&r1=659158&r2=659159&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/BeanModelSourceImplTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/BeanModelSourceImplTest.java Thu May 22 09:57:45 2008
@@ -19,6 +19,7 @@
 import org.apache.tapestry5.beaneditor.BeanModel;
 import org.apache.tapestry5.beaneditor.PropertyModel;
 import org.apache.tapestry5.beaneditor.RelativePosition;
+import org.apache.tapestry5.internal.PropertyOrderBean;
 import org.apache.tapestry5.internal.test.InternalBaseTestCase;
 import org.apache.tapestry5.internal.transform.pages.ReadOnlyBean;
 import org.apache.tapestry5.ioc.Messages;
@@ -680,4 +681,22 @@
 
         verify();
     }
+
+    @Test
+    public void reoder_from_annotation()
+    {
+        ComponentResources resources = mockComponentResources();
+        Messages messages = mockMessages();
+
+        train_getMessages(resources, messages);
+        stub_contains(messages, false);
+
+        replay();
+
+        BeanModel model = source.create(PropertyOrderBean.class, true, resources);
+
+        assertEquals(model.getPropertyNames(), Arrays.asList("third", "first", "second"));
+
+        verify();
+    }
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/StoogeBean.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/StoogeBean.java?rev=659159&r1=659158&r2=659159&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/StoogeBean.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/StoogeBean.java Thu May 22 09:57:45 2008
@@ -1,4 +1,4 @@
-// Copyright 2007 The Apache Software Foundation
+// Copyright 2007, 2008 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.
@@ -14,9 +14,9 @@
 
 package org.apache.tapestry5.internal.services;
 
-import org.apache.tapestry5.beaneditor.OrderAfter;
-import org.apache.tapestry5.beaneditor.OrderBefore;
+import org.apache.tapestry5.beaneditor.ReorderProperties;
 
+@ReorderProperties("larry,moe,shemp,curly")
 public class StoogeBean
 {
     private int moe, larry, curly, shemp;
@@ -26,13 +26,11 @@
         return moe;
     }
 
-    @OrderAfter("shemp")
     public int getCurly()
     {
         return curly;
     }
 
-    @OrderBefore("moe")
     public int getLarry()
     {
         return larry;

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java?rev=659159&r1=659158&r2=659159&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java Thu May 22 09:57:45 2008
@@ -47,7 +47,8 @@
             Class propertyType = readMethod == null ? pd.getPropertyType() : GenericsUtils.extractGenericReturnType(
                     beanType, readMethod);
 
-            PropertyAdapter pa = new PropertyAdapterImpl(pd.getName(), propertyType, readMethod, pd.getWriteMethod());
+            PropertyAdapter pa = new PropertyAdapterImpl(beanType, pd.getName(), propertyType, readMethod,
+                                                         pd.getWriteMethod());
 
             adapters.put(pa.getName(), pa);
         }

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java?rev=659159&r1=659158&r2=659159&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java Thu May 22 09:57:45 2008
@@ -19,11 +19,14 @@
 import org.apache.tapestry5.ioc.services.PropertyAdapter;
 
 import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 
 public class PropertyAdapterImpl implements PropertyAdapter
 {
+    private final Class beanType;
+
     private final String name;
 
     private final Method readMethod;
@@ -34,8 +37,19 @@
 
     private final boolean castRequired;
 
-    public PropertyAdapterImpl(String name, Class type, Method readMethod, Method writeMethod)
+    /**
+     * Have we tried to resolve from the property name to the field yet?
+     */
+    private boolean fieldCheckedFor;
+    /**
+     * The field from the containing type that matches this property name (may be null if not found, or not checked for
+     * yet).
+     */
+    private Field field;
+
+    public PropertyAdapterImpl(Class beanType, String name, Class type, Method readMethod, Method writeMethod)
     {
+        this.beanType = notNull(beanType, "beanType");
         this.name = notBlank(name, "name");
         this.type = notNull(type, "type");
 
@@ -129,9 +143,43 @@
 
         if (result == null && writeMethod != null) result = writeMethod.getAnnotation(annotationClass);
 
+        if (result == null) result = getAnnotationFromField(annotationClass);
+
         return result;
     }
 
+    private <T extends Annotation> T getAnnotationFromField(Class<T> annotationClass)
+    {
+        Field field = getField();
+
+        return field == null ? null : field.getAnnotation(annotationClass);
+    }
+
+
+    private synchronized Field getField()
+    {
+        if (!fieldCheckedFor)
+        {
+            // There's an assumption here, that the fields match the property name (we ignore case
+            // which leads to a manageable ambiguity) and that the field and the getter/setter
+            // are in the same class (i.e., that we don't have a getter exposing a protected field inherted
+            // from a base class, or some other oddity).
+
+            for (Field f : beanType.getDeclaredFields())
+            {
+                if (f.getName().equalsIgnoreCase(name))
+                {
+                    field = f;
+                    break;
+                }
+            }
+
+            fieldCheckedFor = true;
+        }
+
+        return field;
+    }
+
     public boolean isCastRequired()
     {
         return castRequired;

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAdapter.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAdapter.java?rev=659159&r1=659158&r2=659159&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAdapter.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAdapter.java Thu May 22 09:57:45 2008
@@ -19,8 +19,9 @@
 import java.lang.reflect.Method;
 
 /**
- * Provides access to a single property within a class. Acts as an {@link AnnotationProvider}; when searching for
- * annotations, the read method (if present) is checked first, followed by the write method.
+ * Provides access to a single property within a class. Acts as an {@link org.apache.tapestry5.ioc.AnnotationProvider};
+ * when searching for annotations, the read method (if present) is checked first, followed by the write method, followed
+ * by the underlying field (when the property name matches the field name).
  *
  * @see org.apache.tapestry5.ioc.services.ClassPropertyAdapter
  */

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImplTest.java?rev=659159&r1=659158&r2=659159&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImplTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImplTest.java Thu May 22 09:57:45 2008
@@ -14,6 +14,8 @@
 
 package org.apache.tapestry5.ioc.internal.services;
 
+import org.apache.tapestry5.beaneditor.DataType;
+import org.apache.tapestry5.beaneditor.Validate;
 import org.apache.tapestry5.ioc.Registry;
 import org.apache.tapestry5.ioc.annotations.Scope;
 import org.apache.tapestry5.ioc.internal.IOCInternalTestCase;
@@ -39,8 +41,11 @@
 
     public static class Bean
     {
+        @DataType("fred")
+        @Validate("field-value-overridden")
         private int value;
 
+        @Validate("getter-value-overrides")
         public int getValue()
         {
             return value;
@@ -453,6 +458,25 @@
     }
 
     @Test
+    public void get_annotation_will_read_field()
+    {
+        PropertyAdapter pa = access.getAdapter(Bean.class).getPropertyAdapter("value");
+
+        DataType dt = pa.getAnnotation(DataType.class);
+
+        assertNotNull(dt);
+        assertEquals(dt.value(), "fred");
+    }
+
+    @Test
+    public void field_annotation_overridden_by_getter_annotation()
+    {
+        PropertyAdapter pa = access.getAdapter(Bean.class).getPropertyAdapter("value");
+
+        assertEquals(pa.getAnnotation(Validate.class).value(), "getter-value-overrides");
+    }
+
+    @Test
     public void using_generics()
     {
         ClassPropertyAdapter cpa1 = access.getAdapter(StringLongPair.class);