Updated Branches:
  refs/heads/master 6c8da1857 -> 37efe7eff

Convert TestNG to Spock


Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/37efe7ef
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/37efe7ef
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/37efe7ef

Branch: refs/heads/master
Commit: 37efe7effd8e49d7dc9d402d3fba298d5c8d7a44
Parents: 6c8da18
Author: Howard M. Lewis Ship <[email protected]>
Authored: Mon May 21 11:10:30 2012 -0700
Committer: Howard M. Lewis Ship <[email protected]>
Committed: Mon May 21 11:10:30 2012 -0700

----------------------------------------------------------------------
 .../services/ClassPropertyAdapterImpl.java         |    4 +-
 .../ioc/internal/services/PropertyAdapterImpl.java |   23 +-
 .../services/PropertyShadowBuilderImpl.java        |   32 +-
 .../ioc/internal/services/ServiceMessages.java     |   14 -
 .../internal/services/ServiceStrings.properties    |    3 -
 .../services/PropertyAccessImplSpec.groovy         |  708 +++++++++++++
 .../ioc/services/GeneralIntegrationSpec.groovy     |   26 +
 .../tapestry5/ioc/internal/services/Bean.java      |   39 +
 .../ioc/internal/services/BeanSubclass.java        |   25 +
 .../internal/services/PropertyAccessImplTest.java  |  775 ---------------
 .../ioc/internal/services/PublicFieldBean.java     |    7 +
 .../internal/services/ShadowedPublicFieldBean.java |   18 +
 .../apache/tapestry5/ioc/test/BeanSubclass.java    |   25 -
 .../apache/tapestry5/ioc/test/TestBaseTest.java    |    3 +-
 14 files changed, 857 insertions(+), 845 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/37efe7ef/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java
----------------------------------------------------------------------
diff --git 
a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java
 
b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java
index a7cf81d..b96a0c2 100644
--- 
a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java
+++ 
b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007, 2008, 2010, 2011 The Apache Software Foundation
+// Copyright 2006, 2007, 2008, 2010, 2011, 2012 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -82,7 +82,7 @@ public class ClassPropertyAdapterImpl implements 
ClassPropertyAdapter
     {
         String names = InternalUtils.joinSorted(adapters.keySet());
 
-        return String.format("<ClassPropertyAdaptor %s : %s>", 
beanType.getName(), names);
+        return String.format("<ClassPropertyAdaptor %s: %s>", 
beanType.getName(), names);
     }
 
     public List<String> getPropertyNames()

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/37efe7ef/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java
----------------------------------------------------------------------
diff --git 
a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java
 
b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java
index 67315b2..ced7bf2 100644
--- 
a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java
+++ 
b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java
@@ -1,4 +1,4 @@
-// Copyright 2006, 2008, 2010 The Apache Software Foundation
+// Copyright 2006, 2008, 2010, 2012 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@ package org.apache.tapestry5.ioc.internal.services;
 
 import org.apache.tapestry5.ioc.AnnotationProvider;
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.InternalUtils;
 import org.apache.tapestry5.ioc.services.ClassPropertyAdapter;
 import org.apache.tapestry5.ioc.services.PropertyAdapter;
 
@@ -115,7 +116,9 @@ public class PropertyAdapterImpl implements PropertyAdapter
     public Object get(Object instance)
     {
         if (field == null && readMethod == null)
-            throw new 
UnsupportedOperationException(ServiceMessages.readNotSupported(instance, name));
+        {
+            throw new UnsupportedOperationException(String.format("Class %s 
does not provide an accessor ('getter') method for property '%s'.", 
toClassName(instance), name));
+        }
 
         Throwable fail;
 
@@ -139,7 +142,12 @@ public class PropertyAdapterImpl implements PropertyAdapter
     public void set(Object instance, Object value)
     {
         if (field == null && writeMethod == null)
-            throw new 
UnsupportedOperationException(ServiceMessages.writeNotSupported(instance, 
name));
+        {
+            throw new UnsupportedOperationException(String.format("Class %s 
does not provide a mutator ('setter') method for property '%s'.",
+                    toClassName(instance),
+                    name
+            ));
+        }
 
         Throwable fail;
 
@@ -159,7 +167,14 @@ public class PropertyAdapterImpl implements PropertyAdapter
             fail = ex;
         }
 
-        throw new RuntimeException(ServiceMessages.writeFailure(name, 
instance, fail), fail);
+        throw new RuntimeException(String.format("Error updating property '%s' 
of %s: %s",
+                name, toClassName(instance),
+                InternalUtils.toMessage(fail)), fail);
+    }
+
+    private String toClassName(Object instance)
+    {
+        return instance == null ? "<null>" : instance.getClass().getName();
     }
 
     public <T extends Annotation> T getAnnotation(Class<T> annotationClass)

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/37efe7ef/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyShadowBuilderImpl.java
----------------------------------------------------------------------
diff --git 
a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyShadowBuilderImpl.java
 
b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyShadowBuilderImpl.java
index fe09b1e..187f25f 100644
--- 
a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyShadowBuilderImpl.java
+++ 
b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyShadowBuilderImpl.java
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007, 2010, 2011 The Apache Software Foundation
+// Copyright 2006, 2007, 2010, 2011, 2012 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -14,24 +14,10 @@
 
 package org.apache.tapestry5.ioc.internal.services;
 
+import org.apache.tapestry5.ioc.services.*;
+import org.apache.tapestry5.plastic.*;
+
 import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-
-import org.apache.tapestry5.ioc.services.Builtin;
-import org.apache.tapestry5.ioc.services.PlasticProxyFactory;
-import org.apache.tapestry5.ioc.services.PropertyAccess;
-import org.apache.tapestry5.ioc.services.PropertyAdapter;
-import org.apache.tapestry5.ioc.services.PropertyShadowBuilder;
-import org.apache.tapestry5.plastic.ClassInstantiator;
-import org.apache.tapestry5.plastic.Condition;
-import org.apache.tapestry5.plastic.WhenCallback;
-import org.apache.tapestry5.plastic.InstructionBuilder;
-import org.apache.tapestry5.plastic.InstructionBuilderCallback;
-import org.apache.tapestry5.plastic.MethodDescription;
-import org.apache.tapestry5.plastic.PlasticClass;
-import org.apache.tapestry5.plastic.PlasticClassTransformer;
-import org.apache.tapestry5.plastic.PlasticField;
-import org.apache.tapestry5.plastic.PlasticMethod;
 
 public class PropertyShadowBuilderImpl implements PropertyShadowBuilder
 {
@@ -40,9 +26,9 @@ public class PropertyShadowBuilderImpl implements 
PropertyShadowBuilder
     private final PlasticProxyFactory proxyFactory;
 
     public PropertyShadowBuilderImpl(@Builtin
-    PlasticProxyFactory proxyFactory,
+                                     PlasticProxyFactory proxyFactory,
 
-    PropertyAccess propertyAccess)
+                                     PropertyAccess propertyAccess)
     {
         this.proxyFactory = proxyFactory;
         this.propertyAccess = propertyAccess;
@@ -59,7 +45,11 @@ public class PropertyShadowBuilderImpl implements 
PropertyShadowBuilder
             throw new 
RuntimeException(ServiceMessages.noSuchProperty(sourceClass, propertyName));
 
         if (!adapter.isRead())
-            throw new 
RuntimeException(ServiceMessages.readNotSupported(source, propertyName));
+        {
+            throw new RuntimeException(
+                    String.format("Class %s does not provide an accessor 
('getter') method for property '%s'.",
+                            source.getClass().getName(), propertyName));
+        }
 
         if (!propertyType.isAssignableFrom(adapter.getType()))
             throw new 
RuntimeException(ServiceMessages.propertyTypeMismatch(propertyName, sourceClass,

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/37efe7ef/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceMessages.java
----------------------------------------------------------------------
diff --git 
a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceMessages.java
 
b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceMessages.java
index f35aaa5..ad4c5b5 100644
--- 
a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceMessages.java
+++ 
b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceMessages.java
@@ -32,26 +32,12 @@ public class ServiceMessages
         return MESSAGES.format("no-such-property", clazz.getName(), 
propertyName);
     }
 
-    public static String readNotSupported(Object instance, String propertyName)
-    {
-        return MESSAGES.format("read-not-supported", 
instance.getClass().getName(), propertyName);
-    }
-
-    public static String writeNotSupported(Object instance, String 
propertyName)
-    {
-        return MESSAGES.format("write-not-supported", 
instance.getClass().getName(), propertyName);
-    }
 
     public static String readFailure(String propertyName, Object instance, 
Throwable cause)
     {
         return MESSAGES.format("read-failure", propertyName, instance, cause);
     }
 
-    public static String writeFailure(String propertyName, Object instance, 
Throwable cause)
-    {
-        return MESSAGES.format("write-failure", propertyName, instance, cause);
-    }
-
     public static String propertyTypeMismatch(String propertyName, Class 
sourceClass, Class propertyType,
                                               Class expectedType)
     {

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/37efe7ef/tapestry-ioc/src/main/resources/org/apache/tapestry5/ioc/internal/services/ServiceStrings.properties
----------------------------------------------------------------------
diff --git 
a/tapestry-ioc/src/main/resources/org/apache/tapestry5/ioc/internal/services/ServiceStrings.properties
 
b/tapestry-ioc/src/main/resources/org/apache/tapestry5/ioc/internal/services/ServiceStrings.properties
index 2bc3922..b16ae75 100644
--- 
a/tapestry-ioc/src/main/resources/org/apache/tapestry5/ioc/internal/services/ServiceStrings.properties
+++ 
b/tapestry-ioc/src/main/resources/org/apache/tapestry5/ioc/internal/services/ServiceStrings.properties
@@ -13,10 +13,7 @@
 # limitations under the License.
 
 no-such-property=Class %s does not contain a property named '%s'.
-read-not-supported=Class %s does not provide an accessor ('getter') method for 
property '%s'.
-write-not-supported=Class %s does not provide an mutator ('setter') method for 
property '%s'.
 read-failure=Error reading property '%s' of %s: %s
-write-failure=Error updating property '%s' of %s: %s
 property-type-mismatch=Property '%s' of class %s is of type %s, which is not 
assignable to type %s.
 shutdown-listener-error=Error notifying %s of registry shutdown: %s
 recursive-symbol=Symbol '%s' is defined in terms of itself (%s).

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/37efe7ef/tapestry-ioc/src/test/groovy/org/apache/tapestry5/ioc/internal/services/PropertyAccessImplSpec.groovy
----------------------------------------------------------------------
diff --git 
a/tapestry-ioc/src/test/groovy/org/apache/tapestry5/ioc/internal/services/PropertyAccessImplSpec.groovy
 
b/tapestry-ioc/src/test/groovy/org/apache/tapestry5/ioc/internal/services/PropertyAccessImplSpec.groovy
new file mode 100644
index 0000000..795f988
--- /dev/null
+++ 
b/tapestry-ioc/src/test/groovy/org/apache/tapestry5/ioc/internal/services/PropertyAccessImplSpec.groovy
@@ -0,0 +1,708 @@
+package org.apache.tapestry5.ioc.internal.services
+
+import org.apache.tapestry5.beaneditor.DataType
+import org.apache.tapestry5.beaneditor.Validate
+import org.apache.tapestry5.ioc.annotations.Scope
+import org.apache.tapestry5.ioc.internal.util.Pair
+import org.apache.tapestry5.ioc.internal.util.StringLongPair
+import org.apache.tapestry5.ioc.services.ClassPropertyAdapter
+import org.apache.tapestry5.ioc.services.PropertyAccess
+
+import java.awt.Image
+import java.lang.reflect.Method
+
+import spock.lang.*
+
+import java.beans.*
+
+class ExceptionBean {
+
+  boolean getFailure() {
+    throw new RuntimeException("getFailure");
+  }
+
+  void setFailure(boolean b) {
+    throw new RuntimeException("setFailure");
+  }
+
+  @Override
+  String toString() {
+    return "PropertyAccessImplSpecBean";
+  }
+}
+
+class UglyBean {
+}
+
+class UglyBeanBeanInfo implements BeanInfo {
+
+  BeanInfo[] getAdditionalBeanInfo() {
+    return new BeanInfo[0];
+  }
+
+  BeanDescriptor getBeanDescriptor() {
+    return null;
+  }
+
+  int getDefaultEventIndex() {
+    return 0;
+  }
+
+  int getDefaultPropertyIndex() {
+    return 0;
+  }
+
+  EventSetDescriptor[] getEventSetDescriptors() {
+    return new EventSetDescriptor[0];
+  }
+
+  Image getIcon(int iconKind) {
+    return null;
+  }
+
+  MethodDescriptor[] getMethodDescriptors() {
+    return new MethodDescriptor[0];
+  }
+
+  PropertyDescriptor[] getPropertyDescriptors() {
+    throw new RuntimeException("This is the UglyBean.");
+  }
+
+}
+
+class ScalaBean {
+
+  private String value;
+
+  String getValue() {
+    return value;
+  }
+
+  void setValue(String value) {
+    this.value = value;
+  }
+
+  String value() {
+    return value;
+  }
+
+  void value_$eq(String value) {
+    this.value = value;
+  }
+}
+
+class ScalaClass {
+
+  private String value;
+
+  String value() {
+    return value;
+  }
+
+  void value_$eq(String value) {
+    this.value = value;
+  }
+}
+
+interface BeanInterface {
+
+  String getValue();
+
+  void setValue(String v);
+
+  String getOtherValue();
+
+  void setOtherValue(String v);
+
+  int getIntValue(); // read-only
+}
+
+abstract class AbstractBean implements BeanInterface {
+  // abstract class implements method from interface
+  private String other;
+
+  String getOtherValue() {
+    return other;
+  }
+
+  void setOtherValue(String v) {
+    other = v;
+  }
+}
+
+class ConcreteBean extends AbstractBean {
+
+  private String value;
+  private int intValue;
+
+  ConcreteBean(int intValue) {
+    this.intValue = intValue;
+  }
+
+  String getValue() {
+    return value;
+  }
+
+  void setValue(String v) {
+    value = v;
+  }
+
+  int getIntValue() {
+    return intValue;
+  }
+}
+
+abstract class GenericBean<T> {
+
+  public T value;
+}
+
+class GenericStringBean extends GenericBean<String> {
+}
+
+class PropertyAccessImplSpec extends Specification {
+
+  @Shared
+  PropertyAccess access = new PropertyAccessImpl()
+
+  @Shared
+  Random random = new Random()
+
+  def "simple read access to a standard bean"() {
+    Bean b = new Bean()
+    int value = random.nextInt()
+
+    when:
+
+    b.value = value
+
+    then:
+
+    access.get(b, "value") == value
+  }
+
+  def "property name access is case insensitive"() {
+    Bean b = new Bean()
+    int value = random.nextInt()
+
+    when:
+
+    b.value = value
+
+    then:
+
+    access.get(b, "VaLUe") == value
+  }
+
+  def "simple write access to a standard bean"() {
+    Bean b = new Bean()
+    int value = random.nextInt()
+
+    when:
+
+    access.set(b, "value", value)
+
+    then:
+
+    b.value == value
+  }
+
+  def "missing properties are an exception"() {
+    Bean b = new Bean()
+
+    when:
+
+    access.get(b, "zaphod")
+
+    then:
+
+    IllegalArgumentException e = thrown()
+
+    e.message == "Class ${b.class.name} does not contain a property named 
'zaphod'."
+  }
+
+  def "it is not possible to update a read-only property"() {
+    Bean b = new Bean()
+
+    when:
+
+    access.set(b, "class", null)
+
+    then:
+
+    UnsupportedOperationException e = thrown()
+
+    e.message == "Class ${b.class.name} does not provide a mutator ('setter') 
method for property 'class'."
+  }
+
+  def "it is not possible to read a write-only property"() {
+    Bean b = new Bean()
+
+    when:
+
+    access.get(b, "writeOnly")
+
+    then:
+
+    UnsupportedOperationException e = thrown()
+
+    e.message == "Class ${b.class.name} does not provide an accessor 
('getter') method for property 'writeOnly'."
+  }
+
+  def "when a getter method throws an exception, the exception is wrapped and 
rethrown"() {
+
+    ExceptionBean b = new ExceptionBean()
+
+    when:
+
+    access.get(b, "failure")
+
+    then:
+
+    RuntimeException e = thrown()
+
+    e.message == "Error reading property 'failure' of ${b}: getFailure"
+  }
+
+  def "when a setter method throws an exception, the exception is wrapped and 
rethrown"() {
+    ExceptionBean b = new ExceptionBean()
+
+    when:
+
+    access.set(b, "failure", false)
+
+    then:
+
+    RuntimeException e = thrown()
+
+    e.message == "Error updating property 'failure' of ${b.class.name}: 
setFailure"
+  }
+
+  @Ignore
+  def "exception throw when introspecting the class is wrapped and rethrown"() 
{
+
+    // Due to Groovy, the exception gets thrown here, not inside
+    // the access.get() method, thus @Ingore (for now)
+
+    UglyBean b = new UglyBean()
+
+    when:
+
+    access.get(b, "google")
+
+    then:
+
+    RuntimeException e = thrown()
+
+    e.message == "java.lang.RuntimeException: This is the UglyBean."
+  }
+
+  def "clearCache() wipes internal cache"() {
+    when:
+
+    ClassPropertyAdapter cpa1 = access.getAdapter Bean
+
+    then:
+
+    cpa1.is(access.getAdapter(Bean))
+
+
+    when:
+
+    access.clearCache()
+
+    then:
+
+    !cpa1.is(access.getAdapter(Bean))
+  }
+
+  def "ClassPropertyAdapter has a useful toString()"() {
+
+    when:
+
+    def cpa = access.getAdapter Bean
+
+    then:
+
+    cpa.toString() == "<ClassPropertyAdaptor ${Bean.class.name}: PI, class, 
readOnly, value, writeOnly>"
+  }
+
+  @Unroll
+  def "expected properties for #beanClass.name property '#propertyName' are 
read=#read, update=#update, castRequired=#castRequired"() {
+
+    when:
+
+    def pa = getPropertyAdapter beanClass, propertyName
+
+    then:
+
+    pa.read == read
+    pa.update == update
+    pa.castRequired == castRequired
+    pa.writeMethod == writeMethod
+    pa.readMethod == readMethod
+
+    where:
+
+    beanClass | propertyName | read  | update | castRequired | writeMethodName 
| readMethodName
+    Bean      | "readOnly"   | true  | false  | false        | null            
| "getReadOnly"
+    Bean      | "writeOnly"  | false | true   | false        | "setWriteOnly"  
| null
+    Bean      | "pi"         | true  | false  | false        | null            
| null
+
+    writeMethod = findMethod beanClass, writeMethodName
+    readMethod = findMethod beanClass, readMethodName
+  }
+
+  def "PropertyAdapter for unknown property name is null"() {
+    when:
+
+    ClassPropertyAdapter cpa = access.getAdapter(Bean)
+
+    then:
+
+    cpa.getPropertyAdapter("google") == null
+  }
+
+  @Unroll
+  def "PropertyAdapter.type for #beanClass.name property '#propertyName' is 
#type.name"() {
+
+    ClassPropertyAdapter cpa = access.getAdapter(beanClass)
+
+    when:
+
+    def adapter = cpa.getPropertyAdapter(propertyName)
+
+    then:
+
+    adapter.type.is(type)
+
+    where:
+
+    beanClass | propertyName | type
+    Bean      | "value"      | int
+    Bean      | "readOnly"   | String
+    Bean      | "writeOnly"  | boolean
+  }
+
+  def "ClassPropertyAdapter gives access to property names (in sorted 
order)"() {
+    ClassPropertyAdapter cpa = access.getAdapter(Bean)
+
+    expect:
+
+    cpa.propertyNames == ["PI", "class", "readOnly", "value", "writeOnly"]
+  }
+
+  def "public static fields are treated as properties"() {
+    when:
+
+    def adapter =getPropertyAdapter Bean, "pi"
+
+    then:
+
+    adapter.get(null).is(Bean.PI)
+  }
+
+  def "public final static fields may not be updated"() {
+    def adapter =getPropertyAdapter Bean, "pi"
+
+    when:
+
+    adapter.set(null, 3.0d)
+
+    then:
+
+    RuntimeException e = thrown()
+
+    e.message.contains "final"
+    e.message.contains "PI"
+  }
+
+  def "super interface methods are inherited by sub-interface"() {
+    when:
+
+    ClassPropertyAdapter cpa = access.getAdapter SubInterface
+
+    then:
+
+    cpa.propertyNames == ["grandParentProperty", "parentProperty", 
"subProperty"]
+  }
+
+  def "indexed properties are ignored"() {
+    when:
+
+    ClassPropertyAdapter cpa = access.getAdapter BeanWithIndexedProperty
+
+    then:
+
+    cpa.propertyNames == ["class", "primitiveProperty"]
+  }
+
+  def "getAnnotation() when annotation is not present is null"() {
+
+    when:
+
+    def pa = getPropertyAdapter AnnotatedBean, "readWrite"
+
+    then:
+
+    pa.getAnnotation(Scope) == null
+  }
+
+  def "getAnnotation() with annotation on setter method"() {
+
+    when:
+
+    def pa = getPropertyAdapter AnnotatedBean, "annotationOnWrite"
+
+    then:
+
+    pa.getAnnotation(Scope).value() == "onwrite"
+  }
+
+  def "annotation on getter method overrides annotation on setter method"() {
+    def pa =getPropertyAdapter AnnotatedBean, "annotationOnRead"
+
+    when:
+
+    Scope annotation = pa.getAnnotation(Scope)
+
+    then:
+
+    annotation.value() == "onread"
+  }
+
+  def "getAnnotation() works on read-only properties, skipping the missing 
setter method"() {
+
+    when:
+
+    def pa = getPropertyAdapter AnnotatedBean, "readOnly"
+
+    then:
+
+    pa.getAnnotation(Scope) == null
+  }
+
+  def "annotations directly on fields are located"() {
+    when:
+
+    def pa = access.getAdapter(Bean).getPropertyAdapter("value")
+
+    then:
+
+    pa.getAnnotation(DataType).value() == "fred"
+  }
+
+  @Issue("TAPESTY-2448")
+  def "getAnnotation() will find annotations from an inherited field in a 
super-class"() {
+    when:
+
+    def pa = getPropertyAdapter BeanSubclass, "value"
+
+    then:
+
+    pa.getAnnotation(DataType).value() == "fred"
+  }
+
+  def "annotations on a getter or setter method override annotations on the 
field"() {
+    when:
+
+    def pa = getPropertyAdapter Bean, "value"
+
+    then:
+
+    pa.getAnnotation(Validate).value() == "getter-value-overrides"
+  }
+
+  def "PropertyAdapter.type understands (simple) generic signatures"() {
+    def cpa1 = access.getAdapter(StringLongPair)
+
+    when:
+
+    def key = cpa1.getPropertyAdapter("key")
+
+    then:
+
+    key.type == String
+    key.castRequired
+    key.declaringClass == Pair
+
+    when:
+
+    def value = cpa1.getPropertyAdapter("value")
+
+    then:
+
+    value.type == Long
+    value.castRequired
+
+    when:
+
+    def cpa2 = access.getAdapter(Pair)
+    def pkey = cpa2.getPropertyAdapter("key")
+
+    then:
+
+    pkey.type == Object
+    !pkey.castRequired
+
+    when:
+
+    def pvalue = cpa2.getPropertyAdapter("value")
+
+    then:
+
+    pvalue.type == Object
+    !pvalue.castRequired
+  }
+
+  def "PropertyAdapter prefers JavaBeans property method names to Scala method 
names"() {
+    when:
+
+    def pa = getPropertyAdapter ScalaBean, "value"
+
+    then:
+
+    pa.readMethod.name == "getValue"
+    pa.writeMethod.name == "setValue"
+  }
+
+  def "PropertyAdapter understands Scala accessor method naming"() {
+    when:
+
+    def pa = getPropertyAdapter ScalaClass, "value"
+
+    then:
+
+    pa.readMethod.name == "value"
+    pa.writeMethod.name == 'value_$eq'
+  }
+
+  def "PropertyAccess exposes public fields as if they were properties"() {
+    when:
+
+    def pa = getPropertyAdapter PublicFieldBean, "value"
+
+    then:
+
+    pa.field
+    pa.read
+    pa.update
+
+    when:
+
+    PublicFieldBean bean = new PublicFieldBean()
+
+    pa.set(bean, "fred")
+
+    then:
+
+    bean.value == "fred"
+
+    when:
+
+    bean.value = "barney"
+
+    then:
+
+    pa.get(bean) == "barney"
+  }
+
+  def "access to property is favored over public field when the names are the 
same"() {
+    def bean = new ShadowedPublicFieldBean()
+
+    when:
+
+    def pa = getPropertyAdapter ShadowedPublicFieldBean, "value"
+
+    then:
+
+    !pa.field
+
+    when:
+
+    pa.set(bean, "fred")
+
+    then:
+
+    bean.@value == null
+
+    when:
+
+    bean.@value = "barney"
+    bean.value = "wilma"
+
+    then:
+
+    pa.get(bean) == "wilma"
+  }
+
+  def "a property defined by an unimplemented inteface method of an abstract 
class is accessible"() {
+    AbstractBean bean = new ConcreteBean(33)
+    def ca = access.getAdapter(AbstractBean)
+
+    when:
+
+    def va = ca.getPropertyAdapter("value")
+
+    then:
+
+    !va.field
+
+    when:
+
+    va.set(bean, "hello")
+
+    then:
+
+    va.get(bean) == "hello"
+    bean.value == "hello"
+
+    when:
+
+    def ova = ca.getPropertyAdapter("otherValue")
+
+    then:
+
+    !ova.field
+
+    when:
+
+    ova.set(bean, "other value")
+
+    then:
+
+    ova.get(bean) == "other value"
+    bean.otherValue == "other value"
+
+    when:
+
+    def iva = ca.getPropertyAdapter("intvalue")
+
+    then:
+
+    iva.get(bean) == 33
+    iva.read
+    !iva.update
+    !iva.field
+  }
+
+  def "generic field is recognized"() {
+    when:
+    def pa = getPropertyAdapter GenericStringBean, "value"
+
+    then:
+
+    pa.castRequired
+    pa.type == String
+    pa.declaringClass == GenericBean
+  }
+
+
+  def getPropertyAdapter(clazz, name) {
+    access.getAdapter(clazz).getPropertyAdapter(name)
+  }
+
+  private Method findMethod(Class beanClass, String methodName) {
+    return beanClass.methods.find { it.name == methodName }
+  }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/37efe7ef/tapestry-ioc/src/test/groovy/org/apache/tapestry5/ioc/services/GeneralIntegrationSpec.groovy
----------------------------------------------------------------------
diff --git 
a/tapestry-ioc/src/test/groovy/org/apache/tapestry5/ioc/services/GeneralIntegrationSpec.groovy
 
b/tapestry-ioc/src/test/groovy/org/apache/tapestry5/ioc/services/GeneralIntegrationSpec.groovy
new file mode 100644
index 0000000..d9c217c
--- /dev/null
+++ 
b/tapestry-ioc/src/test/groovy/org/apache/tapestry5/ioc/services/GeneralIntegrationSpec.groovy
@@ -0,0 +1,26 @@
+package org.apache.tapestry5.ioc.services
+
+import org.apache.tapestry5.ioc.AbstractSharedRegistrySpecification
+import org.apache.tapestry5.ioc.internal.services.Bean
+
+
+class GeneralIntegrationSpec extends AbstractSharedRegistrySpecification {
+
+  def "PropertyAccess service is available"() {
+
+    PropertyAccess pa = getService "PropertyAccess", PropertyAccess
+
+    Bean b = new Bean()
+
+    when:
+
+    pa.set(b, "value", 99)
+
+    then:
+
+    b.value == 99
+    pa.get(b, "value") == 99
+  }
+
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/37efe7ef/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/Bean.java
----------------------------------------------------------------------
diff --git 
a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/Bean.java
 
b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/Bean.java
new file mode 100644
index 0000000..3fae5a6
--- /dev/null
+++ 
b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/Bean.java
@@ -0,0 +1,39 @@
+package org.apache.tapestry5.ioc.internal.services;
+
+import org.apache.tapestry5.beaneditor.DataType;
+import org.apache.tapestry5.beaneditor.Validate;
+
+public class Bean
+{
+    public static final Double PI = 3.14;
+
+    @DataType("fred")
+    @Validate("field-value-overridden")
+    private int value;
+
+    @Validate("getter-value-overrides")
+    public int getValue()
+    {
+        return value;
+    }
+
+    public void setValue(int value)
+    {
+        this.value = value;
+    }
+
+    @Override
+    public String toString()
+    {
+        return "PropertyAccessImplSpecBean";
+    }
+
+    public void setWriteOnly(boolean b)
+    {
+    }
+
+    public String getReadOnly()
+    {
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/37efe7ef/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/BeanSubclass.java
----------------------------------------------------------------------
diff --git 
a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/BeanSubclass.java
 
b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/BeanSubclass.java
new file mode 100644
index 0000000..62bffe3
--- /dev/null
+++ 
b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/BeanSubclass.java
@@ -0,0 +1,25 @@
+//  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.ioc.internal.services;
+
+public class BeanSubclass extends Bean
+{
+    private boolean flag;
+
+    public boolean isFlag()
+    {
+        return flag;
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/37efe7ef/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImplTest.java
----------------------------------------------------------------------
diff --git 
a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImplTest.java
 
b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImplTest.java
deleted file mode 100644
index ff00019..0000000
--- 
a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImplTest.java
+++ /dev/null
@@ -1,775 +0,0 @@
-// Copyright 2006, 2007, 2008, 2010 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.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;
-import org.apache.tapestry5.ioc.internal.util.Pair;
-import org.apache.tapestry5.ioc.internal.util.StringLongPair;
-import org.apache.tapestry5.ioc.services.ClassPropertyAdapter;
-import org.apache.tapestry5.ioc.services.PropertyAccess;
-import org.apache.tapestry5.ioc.services.PropertyAdapter;
-import org.testng.annotations.Test;
-
-import java.awt.*;
-import java.beans.*;
-import java.util.Arrays;
-import java.util.Random;
-
-public class PropertyAccessImplTest extends IOCInternalTestCase
-{
-    private static final String CLASS_NAME = 
PropertyAccessImplTest.class.getName();
-
-    private PropertyAccess access = new PropertyAccessImpl();
-
-    private Random random = new Random();
-
-    public static class Bean
-    {
-        public static final Double PI = 3.14;
-
-        @DataType("fred")
-        @Validate("field-value-overridden")
-        private int value;
-
-        @Validate("getter-value-overrides")
-        public int getValue()
-        {
-            return value;
-        }
-
-        public void setValue(int value)
-        {
-            this.value = value;
-        }
-
-        @Override
-        public String toString()
-        {
-            return "PropertyUtilsTestBean";
-        }
-
-        public void setWriteOnly(boolean b)
-        {
-        }
-
-        public String getReadOnly()
-        {
-            return null;
-        }
-    }
-
-    public static class BeanSubclass extends Bean
-    {
-
-    }
-
-    public static class ExceptionBean
-    {
-        public boolean getFailure()
-        {
-            throw new RuntimeException("getFailure");
-        }
-
-        public void setFailure(boolean b)
-        {
-            throw new RuntimeException("setFailure");
-        }
-
-        @Override
-        public String toString()
-        {
-            return "PropertyUtilsExceptionBean";
-        }
-    }
-
-    public static class UglyBean
-    {
-    }
-
-    public static class UglyBeanBeanInfo implements BeanInfo
-    {
-
-        public BeanInfo[] getAdditionalBeanInfo()
-        {
-            return new BeanInfo[0];
-        }
-
-        public BeanDescriptor getBeanDescriptor()
-        {
-            return null;
-        }
-
-        public int getDefaultEventIndex()
-        {
-            return 0;
-        }
-
-        public int getDefaultPropertyIndex()
-        {
-            return 0;
-        }
-
-        public EventSetDescriptor[] getEventSetDescriptors()
-        {
-            return new EventSetDescriptor[0];
-        }
-
-        public Image getIcon(int iconKind)
-        {
-            return null;
-        }
-
-        public MethodDescriptor[] getMethodDescriptors()
-        {
-            return new MethodDescriptor[0];
-        }
-
-        public PropertyDescriptor[] getPropertyDescriptors()
-        {
-            throw new RuntimeException("This is the UglyBean.");
-        }
-
-    }
-
-    public static class ScalaBean
-    {
-        private String value;
-
-        public String getValue()
-        {
-            return value;
-        }
-
-        public void setValue(String value)
-        {
-            this.value = value;
-        }
-
-        public String value()
-        {
-            return value;
-        }
-
-        public void value_$eq(String value)
-        {
-            this.value = value;
-        }
-    }
-
-    public static class ScalaClass
-    {
-        private String value;
-
-        public String value()
-        {
-            return value;
-        }
-
-        public void value_$eq(String value)
-        {
-            this.value = value;
-        }
-    }
-
-    public static class BooleanHolder
-    {
-        private boolean flag;
-
-        public boolean isFlag()
-        {
-            return flag;
-        }
-
-        public void setFlag(boolean flag)
-        {
-            this.flag = flag;
-        }
-    }
-
-    public static class PublicFieldBean
-    {
-        public String value;
-    }
-
-    public static class ShadowedPublicFieldBean
-    {
-        private String _value;
-
-        public String value;
-
-        public String getValue()
-        {
-            return _value;
-        }
-
-        public void setValue(String value)
-        {
-            _value = value;
-        }
-    }
-
-    public static abstract class GenericBean<T>
-    {
-        public T value;
-    }
-
-    public static class GenericStringBean extends GenericBean<String>
-    {
-    }
-
-    public static interface BeanInterface
-    {
-        String getValue();
-
-        void setValue(String v);
-
-        String getOtherValue();
-
-        void setOtherValue(String v);
-
-        int getIntValue(); // read-only
-    }
-
-    public static abstract class AbstractBean implements BeanInterface
-    {
-        // abstract class implements method from interface
-        private String other;
-
-        public String getOtherValue()
-        {
-            return other;
-        }
-
-        public void setOtherValue(String v)
-        {
-            other = v;
-        }
-    }
-
-    public static class ConcreteBean extends AbstractBean
-    {
-        private String value;
-        private int intValue;
-
-        public ConcreteBean(int intValue)
-        {
-            this.intValue = intValue;
-        }
-
-        public String getValue()
-        {
-            return value;
-        }
-
-        public void setValue(String v)
-        {
-            value = v;
-        }
-
-        public int getIntValue()
-        {
-            return intValue;
-        }
-    }
-
-    @Test
-    public void simple_read_access()
-    {
-        Bean b = new Bean();
-
-        int value = random.nextInt();
-
-        b.setValue(value);
-
-        assertEquals(access.get(b, "value"), value);
-    }
-
-    @Test
-    public void property_name_case_is_ignored_on_read()
-    {
-        Bean b = new Bean();
-
-        int value = random.nextInt();
-
-        b.setValue(value);
-
-        assertEquals(access.get(b, "VALUE"), value);
-    }
-
-    @Test
-    public void simple_write_access()
-    {
-        Bean b = new Bean();
-
-        int value = random.nextInt();
-
-        access.set(b, "value", value);
-
-        assertEquals(b.getValue(), value);
-    }
-
-    @Test
-    public void property_name_case_is_ignored_on_write()
-    {
-        Bean b = new Bean();
-
-        int value = random.nextInt();
-
-        access.set(b, "VALUE", value);
-
-        assertEquals(b.getValue(), value);
-    }
-
-    @Test
-    public void missing_property()
-    {
-        Bean b = new Bean();
-
-        try
-        {
-            access.get(b, "zaphod");
-
-            unreachable();
-        } catch (IllegalArgumentException ex)
-        {
-            assertEquals(ex.getMessage(), "Class " + CLASS_NAME + "$Bean does 
not "
-                    + "contain a property named 'zaphod'.");
-        }
-    }
-
-    @Test
-    public void attempt_to_update_read_only_property()
-    {
-        Bean b = new Bean();
-
-        try
-        {
-            access.set(b, "class", null);
-            unreachable();
-        } catch (UnsupportedOperationException ex)
-        {
-            assertEquals(ex.getMessage(), "Class " + CLASS_NAME
-                    + "$Bean does not provide an mutator ('setter') method for 
property 'class'.");
-        }
-    }
-
-    @Test
-    public void attempt_to_read_from_write_only_property()
-    {
-        Bean b = new Bean();
-
-        try
-        {
-            access.get(b, "writeOnly");
-            unreachable();
-        } catch (UnsupportedOperationException ex)
-        {
-            assertEquals(ex.getMessage(), "Class " + CLASS_NAME
-                    + "$Bean does not provide an accessor ('getter') method 
for property 'writeOnly'.");
-        }
-    }
-
-    @Test
-    public void exception_thrown_inside_getter()
-    {
-        ExceptionBean b = new ExceptionBean();
-
-        try
-        {
-            access.get(b, "failure");
-            unreachable();
-        } catch (RuntimeException ex)
-        {
-            assertEquals(ex.getMessage(), "Error reading property 'failure' of 
PropertyUtilsExceptionBean: getFailure");
-        }
-    }
-
-    @Test
-    public void exception_thrown_inside_setter()
-    {
-        ExceptionBean b = new ExceptionBean();
-
-        try
-        {
-            access.set(b, "failure", false);
-            unreachable();
-        } catch (RuntimeException ex)
-        {
-            assertEquals(ex.getMessage(), "Error updating property 'failure' 
of PropertyUtilsExceptionBean: setFailure");
-        }
-    }
-
-    @Test
-    public void failure_when_introspecting_class()
-    {
-        UglyBean b = new UglyBean();
-
-        try
-        {
-            access.get(b, "google");
-            unreachable();
-        } catch (RuntimeException ex)
-        {
-            assertEquals(ex.getMessage(), "java.lang.RuntimeException: This is 
the UglyBean.");
-        }
-    }
-
-    @Test
-    public void clear_wipes_internal_cache()
-    {
-        ClassPropertyAdapter cpa1 = access.getAdapter(Bean.class);
-
-        assertSame(cpa1.getBeanType(), Bean.class);
-
-        ClassPropertyAdapter cpa2 = access.getAdapter(Bean.class);
-
-        assertSame(cpa2, cpa1);
-
-        access.clearCache();
-
-        ClassPropertyAdapter cpa3 = access.getAdapter(Bean.class);
-
-        assertNotSame(cpa3, cpa1);
-    }
-
-    @Test
-    public void class_property_adapter_toString()
-    {
-        ClassPropertyAdapter cpa = access.getAdapter(Bean.class);
-
-        assertEquals(cpa.toString(), "<ClassPropertyAdaptor " + CLASS_NAME
-                + "$Bean : PI, class, readOnly, value, writeOnly>");
-    }
-
-    @Test
-    public void property_adapter_read_only_property()
-    {
-        ClassPropertyAdapter cpa = access.getAdapter(Bean.class);
-        PropertyAdapter pa = cpa.getPropertyAdapter("readOnly");
-
-        assertTrue(pa.isRead());
-        assertFalse(pa.isUpdate());
-        assertFalse(pa.isCastRequired());
-
-        assertNull(pa.getWriteMethod());
-        assertEquals(pa.getReadMethod(), findMethod(Bean.class, 
"getReadOnly"));
-    }
-
-    @Test
-    public void property_adapter_write_only_property()
-    {
-        ClassPropertyAdapter cpa = access.getAdapter(Bean.class);
-        PropertyAdapter pa = cpa.getPropertyAdapter("writeOnly");
-
-        assertFalse(pa.isRead());
-        assertTrue(pa.isUpdate());
-
-        assertEquals(pa.getWriteMethod(), findMethod(Bean.class, 
"setWriteOnly"));
-        assertNull(pa.getReadMethod());
-    }
-
-    @Test
-    public void class_property_adapter_returns_null_for_unknown_property()
-    {
-        ClassPropertyAdapter cpa = access.getAdapter(Bean.class);
-
-        assertNull(cpa.getPropertyAdapter("google"));
-    }
-
-    @Test
-    public void access_to_property_type()
-    {
-        ClassPropertyAdapter cpa = access.getAdapter(Bean.class);
-
-        assertEquals(cpa.getPropertyAdapter("value").getType(), int.class);
-        assertEquals(cpa.getPropertyAdapter("readOnly").getType(), 
String.class);
-        assertEquals(cpa.getPropertyAdapter("writeOnly").getType(), 
boolean.class);
-    }
-
-    @Test
-    public void property_names()
-    {
-        ClassPropertyAdapter cpa = access.getAdapter(Bean.class);
-
-        assertEquals(cpa.getPropertyNames(), Arrays.asList("PI", "class", 
"readOnly", "value", "writeOnly"));
-    }
-
-    @Test
-    public void read_static_field()
-    {
-        PropertyAdapter adapter = 
access.getAdapter(Bean.class).getPropertyAdapter("pi");
-
-        assertSame(adapter.get(null), Bean.PI);
-    }
-
-    @Test
-    public void static_final_fields_may_not_be_changed()
-    {
-        PropertyAdapter adapter = 
access.getAdapter(Bean.class).getPropertyAdapter("pi");
-
-        try
-        {
-            adapter.set(null, 3.0d);
-            unreachable();
-        } catch (RuntimeException ex)
-        {
-            // The exact text varies from JDK to JDK
-            assertMessageContains(ex, "final", "PI");
-        }
-    }
-
-    @Test
-    public void integration()
-    {
-        Registry registry = buildRegistry();
-
-        PropertyAccess pa = registry.getService("PropertyAccess", 
PropertyAccess.class);
-
-        Bean b = new Bean();
-
-        int value = random.nextInt();
-
-        pa.set(b, "value", value);
-
-        assertEquals(b.getValue(), value);
-
-        registry.shutdown();
-    }
-
-    @Test
-    public void super_interface_methods_inherited_by_sub_interface()
-    {
-        ClassPropertyAdapter cpa = access.getAdapter(SubInterface.class);
-
-        assertEquals(cpa.getPropertyNames(), 
Arrays.asList("grandParentProperty", "parentProperty", "subProperty"));
-    }
-
-    @Test
-    public void indexed_properties_are_ignored()
-    {
-        ClassPropertyAdapter cpa = 
access.getAdapter(BeanWithIndexedProperty.class);
-
-        assertEquals(cpa.getPropertyNames(), Arrays.asList("class", 
"primitiveProperty"));
-    }
-
-    @Test
-    public void get_annotation_when_annotation_not_present()
-    {
-        PropertyAdapter pa = 
access.getAdapter(AnnotatedBean.class).getPropertyAdapter("readWrite");
-
-        assertNull(pa.getAnnotation(Scope.class));
-    }
-
-    @Test
-    public void get_annotation_with_annotation_on_write_method()
-    {
-        PropertyAdapter pa = 
access.getAdapter(AnnotatedBean.class).getPropertyAdapter("annotationOnWrite");
-
-        Scope annotation = pa.getAnnotation(Scope.class);
-        assertNotNull(annotation);
-
-        assertEquals(annotation.value(), "onwrite");
-    }
-
-    @Test
-    public void read_method_annotation_overrides_write_method_annotation()
-    {
-        PropertyAdapter pa = 
access.getAdapter(AnnotatedBean.class).getPropertyAdapter("annotationOnRead");
-
-        Scope annotation = pa.getAnnotation(Scope.class);
-        assertNotNull(annotation);
-
-        assertEquals(annotation.value(), "onread");
-    }
-
-    @Test
-    public void no_write_method_reading_missing_annotation()
-    {
-        PropertyAdapter pa = 
access.getAdapter(AnnotatedBean.class).getPropertyAdapter("readOnly");
-
-        assertNull(pa.getAnnotation(Scope.class));
-    }
-
-    @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");
-    }
-
-    /**
-     * TAPESTRY-2448
-     */
-    @Test
-    public void get_annotation_will_read_inherited_field()
-    {
-        PropertyAdapter pa = 
access.getAdapter(BeanSubclass.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);
-
-        PropertyAdapter pa1 = cpa1.getPropertyAdapter("key");
-        assertSame(pa1.getType(), String.class);
-        assertTrue(pa1.isCastRequired());
-
-        assertSame(pa1.getDeclaringClass(), Pair.class);
-
-        PropertyAdapter pa2 = cpa1.getPropertyAdapter("value");
-        assertSame(pa2.getType(), Long.class);
-        assertTrue(pa2.isCastRequired());
-
-        // On the base class, which defines the generic parameter type 
variables,
-        // the properties just look like Object.
-
-        ClassPropertyAdapter cpa2 = access.getAdapter(Pair.class);
-
-        pa1 = cpa2.getPropertyAdapter("key");
-        assertSame(pa1.getType(), Object.class);
-        assertFalse(pa1.isCastRequired());
-
-        pa2 = cpa2.getPropertyAdapter("value");
-        assertSame(pa2.getType(), Object.class);
-        assertFalse(pa2.isCastRequired());
-
-    }
-
-    @Test
-    public void get_scala_properties_with_bean_accessors()
-    {
-        PropertyAdapter pa = 
access.getAdapter(ScalaBean.class).getPropertyAdapter("value");
-
-        // even thought scala accessors are present the java bean ones should 
be the ones used by Tapestry
-        assertEquals(pa.getReadMethod().getName(), "getValue");
-        assertEquals(pa.getWriteMethod().getName(), "setValue");
-    }
-
-    @Test
-    public void get_scala_properties()
-    {
-        PropertyAdapter pa = 
access.getAdapter(ScalaClass.class).getPropertyAdapter("value");
-
-        assertEquals(pa.getReadMethod().getName(), "value");
-        assertEquals(pa.getWriteMethod().getName(), "value_$eq");
-    }
-
-    @Test
-    public void access_to_public_field()
-    {
-        PropertyAdapter pa = 
access.getAdapter(PublicFieldBean.class).getPropertyAdapter("value");
-
-        assertTrue(pa.isField());
-        assertTrue(pa.isRead());
-        assertTrue(pa.isUpdate());
-
-        PublicFieldBean bean = new PublicFieldBean();
-
-        pa.set(bean, "fred");
-
-        assertEquals(bean.value, "fred");
-
-        bean.value = "barney";
-
-        assertEquals(pa.get(bean), "barney");
-    }
-
-    @Test
-    public void property_is_favored_over_public_field()
-    {
-        PropertyAdapter pa = 
access.getAdapter(ShadowedPublicFieldBean.class).getPropertyAdapter("value");
-
-        assertFalse(pa.isField());
-
-        ShadowedPublicFieldBean bean = new ShadowedPublicFieldBean();
-
-        pa.set(bean, "fred");
-
-        assertNull(bean.value);
-
-        bean.value = "barney";
-        bean.setValue("wilma");
-
-        assertEquals(pa.get(bean), "wilma");
-    }
-
-    @Test
-    public void 
access_property_from_unimplemented_interface_in_abstract_base_class()
-    {
-        AbstractBean bean = new ConcreteBean(33);
-
-        PropertyAdapter valueAdapter = 
access.getAdapter(AbstractBean.class).getPropertyAdapter("value");
-
-        assertNotNull(valueAdapter);
-        assertFalse(valueAdapter.isField());
-
-        valueAdapter.set(bean, "Hello");
-
-        assertSame(valueAdapter.get(bean), "Hello");
-        assertSame(bean.getValue(), "Hello");
-
-        PropertyAdapter otherValueAdapter = 
access.getAdapter(AbstractBean.class).getPropertyAdapter("otherValue");
-
-        assertNotNull(otherValueAdapter);
-        assertFalse(otherValueAdapter.isField());
-
-        otherValueAdapter.set(bean, "Other Value");
-
-        assertSame(otherValueAdapter.get(bean), "Other Value");
-        assertSame(bean.getOtherValue(), "Other Value");
-
-        PropertyAdapter intValueAdapter = 
access.getAdapter(AbstractBean.class).getPropertyAdapter("intvalue");
-        assertNotNull(intValueAdapter);
-
-        assertEquals(intValueAdapter.get(bean), 33);
-
-        assertTrue(intValueAdapter.isRead());
-        assertFalse(intValueAdapter.isUpdate());
-    }
-
-
-    @Test
-    public void generic_field_is_recognized()
-    {
-        PropertyAdapter pa = 
access.getAdapter(GenericStringBean.class).getPropertyAdapter("value");
-
-        assertTrue(pa.isCastRequired());
-        assertEquals(pa.getType(), String.class);
-        assertSame(pa.getDeclaringClass(), GenericBean.class);
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/37efe7ef/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/PublicFieldBean.java
----------------------------------------------------------------------
diff --git 
a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/PublicFieldBean.java
 
b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/PublicFieldBean.java
new file mode 100644
index 0000000..abb0e3c
--- /dev/null
+++ 
b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/PublicFieldBean.java
@@ -0,0 +1,7 @@
+package org.apache.tapestry5.ioc.internal.services;
+
+public class PublicFieldBean
+{
+    public String value;
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/37efe7ef/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/ShadowedPublicFieldBean.java
----------------------------------------------------------------------
diff --git 
a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/ShadowedPublicFieldBean.java
 
b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/ShadowedPublicFieldBean.java
new file mode 100644
index 0000000..485806e
--- /dev/null
+++ 
b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/ShadowedPublicFieldBean.java
@@ -0,0 +1,18 @@
+package org.apache.tapestry5.ioc.internal.services;
+
+public class ShadowedPublicFieldBean
+{
+    private String _value;
+
+    public String value;
+
+    public String getValue()
+    {
+        return _value;
+    }
+
+    public void setValue(String value)
+    {
+        _value = value;
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/37efe7ef/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/test/BeanSubclass.java
----------------------------------------------------------------------
diff --git 
a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/test/BeanSubclass.java 
b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/test/BeanSubclass.java
deleted file mode 100644
index 2fd0fa2..0000000
--- a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/test/BeanSubclass.java
+++ /dev/null
@@ -1,25 +0,0 @@
-//  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.ioc.test;
-
-public class BeanSubclass extends Bean
-{
-    private boolean flag;
-
-    public boolean isFlag()
-    {
-        return flag;
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/37efe7ef/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/test/TestBaseTest.java
----------------------------------------------------------------------
diff --git 
a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/test/TestBaseTest.java 
b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/test/TestBaseTest.java
index 54bd9ac..03cec2d 100644
--- a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/test/TestBaseTest.java
+++ b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/test/TestBaseTest.java
@@ -1,4 +1,4 @@
-//  Copyright 2008 The Apache Software Foundation
+//  Copyright 2008, 2012 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -14,6 +14,7 @@
 
 package org.apache.tapestry5.ioc.test;
 
+import org.apache.tapestry5.ioc.internal.services.BeanSubclass;
 import org.testng.annotations.Test;
 
 public class TestBaseTest extends TestBase

Reply via email to