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 2010/05/03 23:52:38 UTC
svn commit: r940643 - in /tapestry/tapestry5/trunk:
tapestry-core/src/main/java/org/apache/tapestry5/internal/services/
tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/
tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/...
Author: hlship
Date: Mon May 3 21:52:37 2010
New Revision: 940643
URL: http://svn.apache.org/viewvc?rev=940643&view=rev
Log:
TAP5-1105: BeanModelSource should recognize public field as properties, but doesn't
Modified:
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/internal/services/PropertyConduitSourceImpl.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/internal/util/GenericsUtils.java
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAccess.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-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=940643&r1=940642&r2=940643&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 Mon May 3 21:52:37 2010
@@ -4,7 +4,7 @@
// 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
+// 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,
@@ -99,9 +99,11 @@ public class BeanModelSourceImpl impleme
Method readMethod = pa.getReadMethod();
- Location location = classFactory.getMethodLocation(readMethod);
+ Location location = readMethod == null ? null : classFactory.getMethodLocation(readMethod);
- properties.add(new PropertyOrder(name, computeDepth(readMethod), location.getLine()));
+ int line = location == null ? -1 : location.getLine();
+
+ properties.add(new PropertyOrder(name, computeDepth(readMethod), line));
}
Collections.sort(properties);
@@ -153,16 +155,14 @@ public class BeanModelSourceImpl impleme
return create(beanClass, true, messages);
}
- public <T> BeanModel<T> create(Class<T> beanClass, boolean filterReadOnlyProperties,
- Messages messages)
+ public <T> BeanModel<T> create(Class<T> beanClass, boolean filterReadOnlyProperties, Messages messages)
{
Defense.notNull(beanClass, "beanClass");
Defense.notNull(messages, "messages");
ClassPropertyAdapter adapter = propertyAccess.getAdapter(beanClass);
- BeanModel<T> model = new BeanModelImpl<T>(beanClass, propertyConduitSource, typeCoercer,
- messages, locator);
+ BeanModel<T> model = new BeanModelImpl<T>(beanClass, propertyConduitSource, typeCoercer, messages, locator);
for (final String propertyName : adapter.getPropertyNames())
{
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java?rev=940643&r1=940642&r2=940643&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java Mon May 3 21:52:37 2010
@@ -914,13 +914,13 @@ public class PropertyConduitSourceImpl i
if (type.isArray())
{
Class<?> componentType = type.getComponentType();
-
+
while (componentType.isArray())
{
componentType = componentType.getComponentType();
}
-
- return InternalUtils.lastTerm(componentType.getName())+"_array";
+
+ return InternalUtils.lastTerm(componentType.getName()) + "_array";
}
return InternalUtils.lastTerm(type.getName());
}
@@ -1032,19 +1032,7 @@ public class PropertyConduitSourceImpl i
if (adapter == null)
{
- ExpressionTermInfo fieldInfo = infoForPublicField(activeType, propertyName);
-
- if (fieldInfo != null)
- return fieldInfo;
-
- Set<String> names = CollectionFactory.newSet();
-
- names.addAll(classAdapter.getPropertyNames());
-
- for (Field f : activeType.getFields())
- {
- names.add(f.getName());
- }
+ List<String> names = classAdapter.getPropertyNames();
throw new UnknownValueException(String.format(
"Class %s does not contain a property (or public field) named '%s'.", activeType.getName(),
@@ -1054,60 +1042,6 @@ public class PropertyConduitSourceImpl i
return createExpressionTermInfoForProperty(adapter);
}
- private ExpressionTermInfo infoForPublicField(Class activeType, String fieldName)
- {
- // Iterate over all public fields of the type (or its super classes)
-
- for (final Field field : activeType.getFields())
- {
- if (field.getName().equalsIgnoreCase(fieldName)) { return new ExpressionTermInfo()
- {
- public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
- {
- return field.getAnnotation(annotationClass);
- }
-
- public boolean isCastRequired()
- {
- return false;
- }
-
- public Method getWriteMethod()
- {
- return null;
- }
-
- public Class getType()
- {
- return field.getType();
- }
-
- public Method getReadMethod()
- {
- // TODO Auto-generated method stub
- return null;
- }
-
- public String getPropertyName()
- {
- return field.getName();
- }
-
- public String getDescription()
- {
- return "field " + field.getName();
- }
-
- public boolean isField()
- {
- return true;
- }
- }; }
- }
-
- return null;
- }
-
private ExpressionTermInfo createExpressionTermInfoForProperty(final PropertyAdapter adapter)
{
return new ExpressionTermInfo()
@@ -1149,7 +1083,7 @@ public class PropertyConduitSourceImpl i
public boolean isField()
{
- return false;
+ return adapter.isField();
}
};
}
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=940643&r1=940642&r2=940643&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 Mon May 3 21:52:37 2010
@@ -1,10 +1,10 @@
-// Copyright 2006, 2007, 2008 The Apache Software Foundation
+// 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
+// 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,
@@ -21,6 +21,7 @@ import org.apache.tapestry5.ioc.services
import org.apache.tapestry5.ioc.services.PropertyAdapter;
import java.beans.PropertyDescriptor;
+import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
@@ -40,18 +41,34 @@ public class ClassPropertyAdapterImpl im
// Indexed properties will have a null propertyType (and a non-null
// indexedPropertyType). We ignore indexed properties.
- if (pd.getPropertyType() == null) continue;
+ if (pd.getPropertyType() == null)
+ continue;
Method readMethod = pd.getReadMethod();
Class propertyType = readMethod == null ? pd.getPropertyType() : GenericsUtils.extractGenericReturnType(
beanType, readMethod);
- PropertyAdapter pa = new PropertyAdapterImpl(this, pd.getName(), propertyType, readMethod,
- pd.getWriteMethod());
+ PropertyAdapter pa = new PropertyAdapterImpl(this, pd.getName(), propertyType, readMethod, pd
+ .getWriteMethod());
adapters.put(pa.getName(), pa);
}
+
+ // Now, add any public fields that do not conflict
+
+ for (Field f : beanType.getFields())
+ {
+ String name = f.getName();
+
+ if (!adapters.containsKey(name))
+ {
+ Class propertyType = GenericsUtils.extractGenericFieldType(beanType, f);
+ PropertyAdapter pa = new PropertyAdapterImpl(this, name, propertyType, f);
+
+ adapters.put(name, pa);
+ }
+ }
}
public Class getBeanType()
@@ -91,7 +108,8 @@ public class ClassPropertyAdapterImpl im
{
PropertyAdapter pa = adapters.get(name);
- if (pa == null) throw new IllegalArgumentException(ServiceMessages.noSuchProperty(beanType, name));
+ if (pa == null)
+ throw new IllegalArgumentException(ServiceMessages.noSuchProperty(beanType, name));
return 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=940643&r1=940642&r2=940643&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 Mon May 3 21:52:37 2010
@@ -1,10 +1,10 @@
-// Copyright 2006, 2008 The Apache Software Foundation
+// Copyright 2006, 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
+// 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,
@@ -41,8 +41,10 @@ public class PropertyAdapterImpl impleme
private AnnotationProvider annotationProvider;
+ private final Field field;
+
PropertyAdapterImpl(ClassPropertyAdapter classAdapter, String name, Class type, Method readMethod,
- Method writeMethod)
+ Method writeMethod)
{
this.classAdapter = classAdapter;
this.name = name;
@@ -52,6 +54,22 @@ public class PropertyAdapterImpl impleme
this.writeMethod = writeMethod;
castRequired = readMethod != null && readMethod.getReturnType() != type;
+
+ field = null;
+ }
+
+ PropertyAdapterImpl(ClassPropertyAdapter classAdapter, String name, Class type, Field field)
+ {
+ this.classAdapter = classAdapter;
+ this.name = name;
+ this.type = type;
+
+ this.field = field;
+
+ castRequired = field.getType() != type;
+
+ readMethod = null;
+ writeMethod = null;
}
public String getName()
@@ -76,24 +94,27 @@ public class PropertyAdapterImpl impleme
public boolean isRead()
{
- return readMethod != null;
+ return field != null || readMethod != null;
}
public boolean isUpdate()
{
- return writeMethod != null;
+ return field != null || writeMethod != null;
}
public Object get(Object instance)
{
- if (readMethod == null)
+ if (field == null && readMethod == null)
throw new UnsupportedOperationException(ServiceMessages.readNotSupported(instance, name));
Throwable fail;
try
{
- return readMethod.invoke(instance);
+ if (field == null)
+ return readMethod.invoke(instance);
+ else
+ return field.get(instance);
}
catch (InvocationTargetException ex)
{
@@ -109,14 +130,17 @@ public class PropertyAdapterImpl impleme
public void set(Object instance, Object value)
{
- if (writeMethod == null)
+ if (field == null && writeMethod == null)
throw new UnsupportedOperationException(ServiceMessages.writeNotSupported(instance, name));
Throwable fail;
try
{
- writeMethod.invoke(instance, value);
+ if (field == null)
+ writeMethod.invoke(instance, value);
+ else
+ field.set(instance, value);
return;
}
@@ -159,8 +183,7 @@ public class PropertyAdapterImpl impleme
Class cursor = getBeanType();
- out:
- while (cursor != null)
+ out: while (cursor != null)
{
for (Field f : cursor.getDeclaredFields())
{
@@ -195,4 +218,10 @@ public class PropertyAdapterImpl impleme
{
return classAdapter.getBeanType();
}
+
+ public boolean isField()
+ {
+ return field != null;
+ }
+
}
Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/GenericsUtils.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/GenericsUtils.java?rev=940643&r1=940642&r2=940643&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/GenericsUtils.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/GenericsUtils.java Mon May 3 21:52:37 2010
@@ -1,10 +1,10 @@
-// Copyright 2008 The Apache Software Foundation
+// Copyright 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
+// 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,
@@ -14,6 +14,7 @@
package org.apache.tapestry5.ioc.internal.util;
+import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
@@ -22,34 +23,55 @@ import java.lang.reflect.TypeVariable;
/**
* Static methods related to the use of JDK 1.5 generics.
*/
+@SuppressWarnings("unchecked")
public class GenericsUtils
{
/**
* Analyzes the method (often defined in a base class) in the context of a particular concrete implementation of the
* class to establish the generic type of a property. This works when the property type is defined as a class
* generic parameter.
- *
- * @param type base type for evaluation
- * @param method method (possibly from a base class of type) to extract
+ *
+ * @param containingClassType
+ * class containing the method, used to reason about generics
+ * @param method
+ * method (possibly from a base class of type) to extract
* @return the generic type if it may be determined, or the raw type (that is, with type erasure, most often
* Object)
*/
- public static Class extractGenericReturnType(Class type, Method method)
+ public static Class extractGenericReturnType(Class containingClassType, Method method)
{
- Class defaultType = method.getReturnType();
+ return extractGenericType(containingClassType, method.getReturnType(), method.getGenericReturnType());
+ }
- Type genericType = method.getGenericReturnType();
+ /**
+ * Analyzes the field in the context of a particular concrete implementation of the class to establish
+ * the generic type of a (public) field. This works when the field type is defined as a class
+ * generic parameter.
+ *
+ * @param containingClassType
+ * class containing the method, used to reason about generics
+ * @param field
+ * public field to extract type from
+ * @return the generic type if it may be determined, or the raw type (that is, with type erasure, most often
+ * @since 5.2.0
+ */
+ public static Class extractGenericFieldType(Class containingClassType, Field field)
+ {
+ return extractGenericType(containingClassType, field.getType(), field.getGenericType());
+ }
+ private static Class extractGenericType(Class containingClassType, Type defaultType, Type genericType)
+ {
// We can only handle the case where you "lock down" a generic type to a specific type.
if (genericType instanceof TypeVariable)
{
// An odd name for the method that gives you access to the type parameters
- // used when implementing this class. When you say Bean<String>, the first
+ // used when implementing this class. When you say Bean<String>, the first
// type variable of the generic superclass is class String.
- Type superType = type.getGenericSuperclass();
+ Type superType = containingClassType.getGenericSuperclass();
if (superType instanceof ParameterizedType)
{
@@ -66,15 +88,16 @@ public class GenericsUtils
TypeVariable stv = typeVariables[i];
// We're trying to match the name of the type variable that is used as the return type
- // of the method. With that name, we find the corresponding index in the
- // type declarations. With the index, we check superPType for the Class instance
+ // of the method. With that name, we find the corresponding index in the
+ // type declarations. With the index, we check superPType for the Class instance
// that defines it. Generics has lots of other options that we simply can't handle.
if (stv.getName().equals(name))
{
Type actualType = superPType.getActualTypeArguments()[i];
- if (actualType instanceof Class) return (Class) actualType;
+ if (actualType instanceof Class)
+ return (Class) actualType;
break;
}
@@ -83,9 +106,8 @@ public class GenericsUtils
}
}
+ return (Class) defaultType;
- return defaultType;
-
- // P.S. I wrote this and I barely understand it. Fortunately, I have tests ...
+ // P.S. I wrote this and I barely understand it. Fortunately, I have tests ...
}
}
Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAccess.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAccess.java?rev=940643&r1=940642&r2=940643&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAccess.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAccess.java Mon May 3 21:52:37 2010
@@ -1,10 +1,10 @@
-// Copyright 2006 The Apache Software Foundation
+// Copyright 2006, 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
+// 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,
@@ -17,24 +17,30 @@ package org.apache.tapestry5.ioc.service
/**
* A wrapper around the JavaBean Introspector that allows more manageable access to JavaBean properties of objects.
* <p/>
- * <p/>
- * Only provides access to <em>simple</em> properties. Indexed properties are ignored.
+ * Only provides access to <em>simple</em> properties. Indexed properties are ignored.
+ * <p>
+ * Starting in Tapestry 5.2, public fields can now be accessed as if they were properly JavaBean properties. Where there
+ * is a name conflict, the true property will be favored over the field access.
*/
public interface PropertyAccess
{
/**
* Reads the value of a property.
- *
- * @throws UnsupportedOperationException if the property is write only
- * @throws IllegalArgumentException if property does not exist
+ *
+ * @throws UnsupportedOperationException
+ * if the property is write only
+ * @throws IllegalArgumentException
+ * if property does not exist
*/
Object get(Object instance, String propertyName);
/**
* Updates the value of a property.
- *
- * @throws UnsupportedOperationException if the property is read only
- * @throws IllegalArgumentException if property does not exist
+ *
+ * @throws UnsupportedOperationException
+ * if the property is read only
+ * @throws IllegalArgumentException
+ * if property does not exist
*/
void set(Object instance, String propertyName, Object value);
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=940643&r1=940642&r2=940643&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 Mon May 3 21:52:37 2010
@@ -1,10 +1,10 @@
-// Copyright 2006, 2008 The Apache Software Foundation
+// Copyright 2006, 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
+// 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,
@@ -22,51 +22,59 @@ import java.lang.reflect.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).
- *
+ * <p>
+ * Starting in release 5.2, this property may actually be a public field.
+ *
* @see org.apache.tapestry5.ioc.services.ClassPropertyAdapter
*/
+@SuppressWarnings("unchecked")
public interface PropertyAdapter extends AnnotationProvider
{
/**
- * Returns the name of the property.
+ * Returns the name of the property (or public field).
*/
String getName();
/**
- * Returns true if the property is readable (i.e., has a getter method).
+ * Returns true if the property is readable (i.e., has a getter method or is a public field).
*/
boolean isRead();
/**
- * Returns the method used to read the property, or null if the property is not readable.
+ * Returns the method used to read the property, or null if the property is not readable (or is a public field).
*/
public Method getReadMethod();
/**
- * Returns true if the property is writeable (i.e., has a setter method).
+ * Returns true if the property is writeable (i.e., has a setter method or is a public field).
*/
boolean isUpdate();
/**
- * Returns the method used to update the property, or null if the property is not writeable.
+ * Returns the method used to update the property, or null if the property is not writeable (or a public field).
*/
public Method getWriteMethod();
/**
* Reads the property value.
- *
- * @param instance to read from
- * @throws UnsupportedOperationException if the property is write only
+ *
+ * @param instance
+ * to read from
+ * @throws UnsupportedOperationException
+ * if the property is write only
*/
Object get(Object instance);
/**
* Updates the property value. The provided value must not be null if the property type is primitive, and must
* otherwise be of the proper type.
- *
- * @param instance to update
- * @param value new value for the property
- * @throws UnsupportedOperationException if the property is read only
+ *
+ * @param instance
+ * to update
+ * @param value
+ * new value for the property
+ * @throws UnsupportedOperationException
+ * if the property is read only
*/
void set(Object instance, Object value);
@@ -82,7 +90,6 @@ public interface PropertyAdapter extends
*/
boolean isCastRequired();
-
/**
* Returns the {@link org.apache.tapestry5.ioc.services.ClassPropertyAdapter} that provides access to other
* properties defined by the same class.
@@ -90,8 +97,15 @@ public interface PropertyAdapter extends
ClassPropertyAdapter getClassAdapter();
/**
- * Returns the type of bean to which this property belongs. This is the same as {@link
- * org.apache.tapestry5.ioc.services.ClassPropertyAdapter#getBeanType()}.
+ * Returns the type of bean to which this property belongs. This is the same as
+ * {@link org.apache.tapestry5.ioc.services.ClassPropertyAdapter#getBeanType()}.
*/
Class getBeanType();
+
+ /**
+ * Returns true if the property is actually a public field.
+ *
+ * @since 5.2
+ */
+ boolean isField();
}
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=940643&r1=940642&r2=940643&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 Mon May 3 21:52:37 2010
@@ -4,7 +4,7 @@
// 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
+// 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,
@@ -145,7 +145,8 @@ public class PropertyAccessImplTest exte
}
- public static class ScalaBean {
+ public static class ScalaBean
+ {
private String value;
public String getValue()
@@ -169,7 +170,8 @@ public class PropertyAccessImplTest exte
}
}
- public static class ScalaClass {
+ public static class ScalaClass
+ {
private String value;
public String value()
@@ -198,6 +200,37 @@ public class PropertyAccessImplTest exte
}
}
+ 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>
+ {
+ }
+
@Test
public void simple_read_access()
{
@@ -259,8 +292,8 @@ public class PropertyAccessImplTest exte
}
catch (IllegalArgumentException ex)
{
- assertEquals(ex.getMessage(),
- "Class " + CLASS_NAME + "$Bean does not " + "contain a property named 'zaphod'.");
+ assertEquals(ex.getMessage(), "Class " + CLASS_NAME + "$Bean does not "
+ + "contain a property named 'zaphod'.");
}
}
@@ -276,8 +309,8 @@ public class PropertyAccessImplTest exte
}
catch (UnsupportedOperationException ex)
{
- assertEquals(ex.getMessage(),
- "Class " + CLASS_NAME + "$Bean does not provide an mutator ('setter') method for property 'class'.");
+ assertEquals(ex.getMessage(), "Class " + CLASS_NAME
+ + "$Bean does not provide an mutator ('setter') method for property 'class'.");
}
}
@@ -293,8 +326,8 @@ public class PropertyAccessImplTest exte
}
catch (UnsupportedOperationException ex)
{
- assertEquals(ex.getMessage(),
- "Class " + CLASS_NAME + "$Bean does not provide an accessor ('getter') method for property 'writeOnly'.");
+ assertEquals(ex.getMessage(), "Class " + CLASS_NAME
+ + "$Bean does not provide an accessor ('getter') method for property 'writeOnly'.");
}
}
@@ -326,8 +359,7 @@ public class PropertyAccessImplTest exte
}
catch (RuntimeException ex)
{
- assertEquals(ex.getMessage(),
- "Error updating property 'failure' of PropertyUtilsExceptionBean: setFailure");
+ assertEquals(ex.getMessage(), "Error updating property 'failure' of PropertyUtilsExceptionBean: setFailure");
}
}
@@ -370,8 +402,8 @@ public class PropertyAccessImplTest exte
{
ClassPropertyAdapter cpa = access.getAdapter(Bean.class);
- assertEquals(cpa.toString(),
- "<ClassPropertyAdaptor " + CLASS_NAME + "$Bean : class, readOnly, value, writeOnly>");
+ assertEquals(cpa.toString(), "<ClassPropertyAdaptor " + CLASS_NAME
+ + "$Bean : class, readOnly, value, writeOnly>");
}
@Test
@@ -464,8 +496,7 @@ public class PropertyAccessImplTest exte
@Test
public void get_annotation_when_annotation_not_present()
{
- PropertyAdapter pa = access.getAdapter(AnnotatedBean.class)
- .getPropertyAdapter("readWrite");
+ PropertyAdapter pa = access.getAdapter(AnnotatedBean.class).getPropertyAdapter("readWrite");
assertNull(pa.getAnnotation(Scope.class));
}
@@ -563,7 +594,8 @@ public class PropertyAccessImplTest exte
}
@Test
- public void get_scala_properties_with_bean_accessors() {
+ 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
@@ -572,10 +604,59 @@ public class PropertyAccessImplTest exte
}
@Test
- public void get_scala_properties() {
+ 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 generic_field_is_recognized()
+ {
+ PropertyAdapter pa = access.getAdapter(GenericStringBean.class).getPropertyAdapter("value");
+
+ assertTrue(pa.isCastRequired());
+ assertEquals(pa.getType(), String.class);
+ }
}