Author: craigmcc
Date: Fri Apr 29 20:04:15 2005
New Revision: 165376
URL: http://svn.apache.org/viewcvs?rev=165376&view=rev
Log:
Correct property setting logic, per patch, and add unit test case.
PR: Bugzilla #34660
Submitted By: Gary VanMatre <gvanmatre AT comcast.net>
Added:
struts/shale/trunk/clay-plugin/src/test/org/apache/shale/clay/utils/
struts/shale/trunk/clay-plugin/src/test/org/apache/shale/clay/utils/PropUtilsTestCase.java
Modified:
struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/component/chain/PropertyValueCommand.java
struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/utils/PropUtils.java
Modified:
struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/component/chain/PropertyValueCommand.java
URL:
http://svn.apache.org/viewcvs/struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/component/chain/PropertyValueCommand.java?rev=165376&r1=165375&r2=165376&view=diff
==============================================================================
---
struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/component/chain/PropertyValueCommand.java
(original)
+++
struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/component/chain/PropertyValueCommand.java
Fri Apr 29 20:04:15 2005
@@ -23,6 +23,7 @@
import javax.faces.el.ValueBinding;
import org.apache.commons.beanutils.BeanUtils;
+import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.chain.Command;
import org.apache.commons.chain.Context;
import org.apache.commons.logging.Log;
@@ -99,13 +100,7 @@
}
} else {
- try {
- BeanUtils.setProperty(child, attributeBean.getName(),
- attributeBean.getValue());
- } catch (Exception e) {
- PropUtils.setProperty(child, attributeBean.getName(),
- attributeBean.getValue(), null);
- }
+ PropUtils.setProperty(child, attributeBean.getName(),
attributeBean.getValue());
}
return isFinal;
Modified:
struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/utils/PropUtils.java
URL:
http://svn.apache.org/viewcvs/struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/utils/PropUtils.java?rev=165376&r1=165375&r2=165376&view=diff
==============================================================================
---
struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/utils/PropUtils.java
(original)
+++
struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/utils/PropUtils.java
Fri Apr 29 20:04:15 2005
@@ -27,13 +27,18 @@
import java.text.MessageFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.StringTokenizer;
-import java.util.TreeSet;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.shale.clay.component.chain.PropertyValueCommand;
public class PropUtils {
+ private static Log log;
+ static {
+ log = LogFactory.getLog(PropUtils.class);
+ }
+
/**
* <p>A utility method that will format the source object using the
pattern.
* The data type of the source object will determine the formatting
strategy.
@@ -131,7 +136,7 @@
try {
lfmtValue = lFormat.format(lArgs);
} catch (Exception je) {
- je.printStackTrace();
+ log.error(je);
}
} else {
lfmtValue = source.toString();
@@ -184,7 +189,7 @@
source instanceof String) { // decoding the value of a string
if (((String) source).length() == 0)
- return null; // empty string reutrn null
+ return null; // empty string returns null
if ((targetType == java.lang.Boolean.TYPE)
|| (targetType == java.lang.Boolean.class)) {
@@ -261,8 +266,8 @@
for (int i = 0; i < numberPatterns.length; i++) {
try {
numericObj = (Number) lFormat.parseObject((String) source);
- } catch (ParseException je) {
- //je.printStackTrace();
+ } catch (Exception je) {
+ je.printStackTrace();
}
if (numericObj != null)
@@ -344,102 +349,7 @@
return targetObj;
}
- /**
- * <p/>Returns an array of string of all the bean properties. Only looks
at
- * the getter methods so the setters can be overloaded. "True" beans do
not
- * allow the setters to be overloaded.
- *</p>
- */
- public static String[] getPropertyNames(Object bean) {
-
- if (bean == null)
- return new String[0];
-
- Method[] methods = bean.getClass().getMethods();
- TreeSet ts = new TreeSet();
-
- for (int i = 0; i < methods.length; ++i) {
- Method method = methods[i];
- String methodName = method.getName();
- if ((methodName.startsWith("get"))
- && (method.getParameterTypes().length == 0)
- && (method.getModifiers() == 1)
- && (!methodName.endsWith("IsNull"))) {
-
- String attrName =
- methodName.substring(3, 4).toLowerCase()
- + methodName.substring(4);
- ts.add(attrName);
- }
- methodName = null;
- method = null;
- }
-
- String[] names = new String[ts.size()];
- ts.toArray(names);
- methods = null;
- ts = null;
-
- return names;
-
- };
- /**
- * <p>Uses a little reflection action to return an object property from a
bean</p>
- * @param bean source bean holding the property
- * @param propName name of the target property
- * @return the target property or a null value
- */
- public static Object getProperty(Object bean, String propName) {
-
- if (bean == null)
- return null;
-
- Object prop = null;
- Class[] paramTypes = new Class[0];
- Method isNullMethod = null;
- boolean isNullValue = false;
- String methodName =
- "get"
- + propName.substring(0, 1).toUpperCase()
- + propName.substring(1);
-
- String isNullMethodName = methodName + "IsNull";
- Object[] paramValues = new Object[0];
-
- try {
- isNullMethod =
- bean.getClass().getMethod(isNullMethodName, paramTypes);
- Boolean isNull = (Boolean) isNullMethod.invoke(bean, paramValues);
- if (isNull.booleanValue())
- return null;
- } catch (IllegalAccessException e) {
- } catch (InvocationTargetException e) {
- } catch (NoSuchMethodException e) {
- }
-
- try {
- Method method = bean.getClass().getMethod(methodName, paramTypes);
-
- method.setAccessible(true);
- prop = method.invoke(bean, paramValues);
-
- paramValues = null;
- method = null;
-
- } catch (NoSuchMethodException je) {
- je.printStackTrace();
- } catch (IllegalAccessException je) {
- je.printStackTrace();
- } catch (InvocationTargetException je) {
- je.printStackTrace();
- }
-
- paramTypes = null;
- methodName = null;
-
- return prop;
- }
/**
* <p>Sets a simple property on a bean using the reflection API. This
will attempt to normalize
@@ -465,124 +375,92 @@
* @param propValue source value of the property
* @param pattern used to convert data types between the propValue and the
bean properties actual type.
*/
- public static void setProperty(
- Object bean,
- String propName,
- Object propValue,
- String pattern) {
-
+ public static void setProperty(Object bean, String propName,
+ Object propValue, String pattern) {
+
if (bean == null)
return;
-
+
Class[] paramTypes = new Class[0];
- String methodName = null;
-
- try {
-
- Method method = null;
- int tries = 0; //retry counter
-
- next : do {
- tries++; //increment retry counter
- methodName =
- "get"
- + propName.substring(0, 1).toUpperCase()
- + propName.substring(1);
- try {
- method = bean.getClass().getMethod(methodName, paramTypes);
- } catch (Exception e) {
- }
-
- if ((propValue == null) && (method == null))
- return; // must have a getter
- else if ((propValue == null) && (method != null)) {
- if (method.getReturnType().isPrimitive()) {
- // null value for a primitive type is not possible
- propName = propName + "IsNull";
- // check for a rustts invented null state
- propValue = new Boolean(true);
- continue next; //try again
- } else // null assignment for object type is valid
- break next; //exit for loop
- }
-
- } while (tries < 2); //iterations
-
- paramTypes = new Class[1];
-
- // We now should succeed in every case except when setting
- // an object data type to null where there is no getter available
-
- paramTypes[0] =
- (method == null)
- ? propValue.getClass()
- : method.getReturnType();
-
- methodName =
- "set"
- + propName.substring(0, 1).toUpperCase()
+ String[] methodNames = new String[2];
+
+ //look for the getter to find the correct actual parameter type
+ if (propName.startsWith("is"))
+ methodNames[0] = propName;
+ else {
+ methodNames[0] = "get" + propName.substring(0, 1).toUpperCase()
+ + propName.substring(1);
+ methodNames[1] = "is" + propName.substring(0, 1).toUpperCase()
+ propName.substring(1);
- //System.out.println(methodName);
+ }
+
+ //try to make a guess
+ Method method = null;
+ next: for (int i = 0; i < methodNames.length; i++) {
+ if (methodNames[i] == null)
+ break;
+
try {
- method = bean.getClass().getMethod(methodName, paramTypes);
- } catch (Exception e) {
- //no getter found, no setter with the same type as the
incoming property value
- //look for a setter with a signature matching an implemented
interface of the property value
- Class[] interfaces = propValue.getClass().getInterfaces();
- next : for (int i = 0; i < interfaces.length; ++i) {
- try {
- paramTypes[0] = interfaces[i];
- method =
- bean.getClass().getMethod(methodName,
paramTypes);
- } catch (Exception je) {
- continue next;
- }
- break;
+ method = bean.getClass().getMethod(methodNames[i], paramTypes);
+ break next;
+ } catch (SecurityException e) {
+ continue next;
+ } catch (NoSuchMethodException e) {
+ continue next;
+ }
+
+ }
+
+ paramTypes = new Class[1];
+ paramTypes[0] = (method == null) ? propValue.getClass() : method
+ .getReturnType();
+
+ String setterMethodName = null;
+ if (propName.startsWith("is")) {
+ setterMethodName = "set" + propName.substring(2, 3).toUpperCase()
+ + propName.substring(3);
+
+ } else {
+ setterMethodName = "set" + propName.substring(0, 1).toUpperCase()
+ + propName.substring(1);
+ }
+ method = null;
+ try {
+ method = bean.getClass().getMethod(setterMethodName, paramTypes);
+ } catch (Exception e) {
+ // no getter found, no setter with the same type as the incoming
+ // property value
+ // look for a setter with a signature matching an implemented
+ // interface of the property value
+ Class[] interfaces = propValue.getClass().getInterfaces();
+ next: for (int i = 0; i < interfaces.length; ++i) {
+ try {
+ paramTypes[0] = interfaces[i];
+ method = bean.getClass().getMethod(setterMethodName,
+ paramTypes);
+ } catch (Exception je) {
+ continue next;
}
+ break;
}
+ }
+
+ if (method != null) {
+ // convert the source data type to the target type
+ Object[] paramValues = { decodeSimpleProperty(propValue,
paramTypes[0],
+ pattern) };
+ method.setAccessible(true);
- Object[] paramValues =
- { decodeSimpleProperty(propValue, paramTypes[0], pattern)};
-
- if (method != null) {
- method.setAccessible(true);
+ try {
method.invoke(bean, paramValues);
+ } catch (IllegalArgumentException e) {
+ throw new RuntimeException(e);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(e);
}
-
- paramValues = null;
-
- method = null;
-
- } catch (Exception je) {
- je.printStackTrace();
}
-
- paramTypes = null;
- methodName = null;
-
}
-
- /**
- * <p>Copies the state of the source bean's properties into a Map
collection</p>
- * @param bean source bean
- * @return target Map of bean properties
- */
- public static Map describe(Object bean) {
-
- Map attrs = new HashMap();
- String[] propertyNames = getPropertyNames(bean);
- if (propertyNames != null) {
- for (int i = 0; i < propertyNames.length; ++i) {
- attrs.put(
- propertyNames[i],
- getProperty(bean, propertyNames[i]));
- }
- }
-
- propertyNames = null;
-
- return attrs;
- }
-
}
Added:
struts/shale/trunk/clay-plugin/src/test/org/apache/shale/clay/utils/PropUtilsTestCase.java
URL:
http://svn.apache.org/viewcvs/struts/shale/trunk/clay-plugin/src/test/org/apache/shale/clay/utils/PropUtilsTestCase.java?rev=165376&view=auto
==============================================================================
---
struts/shale/trunk/clay-plugin/src/test/org/apache/shale/clay/utils/PropUtilsTestCase.java
(added)
+++
struts/shale/trunk/clay-plugin/src/test/org/apache/shale/clay/utils/PropUtilsTestCase.java
Fri Apr 29 20:04:15 2005
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2004-2005 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.shale.clay.utils;
+
+import junit.framework.TestCase;
+
+/**
+ * <p>
+ * Tests the capabilities of the [EMAIL PROTECTED]
org.apache.shale.clay.utils.PropUtils}
+ * </>
+ */
+public class PropUtilsTestCase extends TestCase {
+
+ private class MockBean {
+ public boolean isEscape() {
+ return isEscape;
+ }
+
+ public void setEscape(boolean isEscape) {
+ this.isEscape = isEscape;
+ }
+
+ public boolean isGlobal() {
+ return isGlobal;
+ }
+
+ public void setGlobal(boolean isGlobal) {
+ this.isGlobal = isGlobal;
+ }
+
+ public double getMaximumDouble() {
+ return maximumDouble;
+ }
+
+ public void setMaximumDouble(double maximumDouble) {
+ this.maximumDouble = maximumDouble;
+ }
+
+ public int getMaximumInt() {
+ return maximumInt;
+ }
+
+ public void setMaximumInt(int maximumInt) {
+ this.maximumInt = maximumInt;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+ private boolean isGlobal = false;
+
+ private boolean isEscape = false;
+
+ private String value = null;
+
+ private int maximumInt = 0;
+
+ private double maximumDouble = 0;
+
+ }
+
+ /**
+ * <p>Tests setting boolean properties from a String
+ * with and without a "is" prefix</p>
+ */
+ public void testBoolean() {
+ MockBean bean = new MockBean();
+
+ PropUtils.setProperty(bean, "isGlobal", "true");
+ assertTrue("isGlobal equals true", bean.isGlobal() == true);
+
+ PropUtils.setProperty(bean, "global", "false");
+ assertTrue("isGlobal equals false", bean.isGlobal() == false);
+
+ PropUtils.setProperty(bean, "isEscape", "true");
+ assertTrue("isEscape equals true", bean.isEscape() == true);
+
+ PropUtils.setProperty(bean, "escape", "false");
+ assertTrue("isEscape equals false", bean.isEscape() == false);
+
+ }
+
+ /**
+ * <p>Tests setting a int property from a String</p>
+ */
+ public void testInteger() {
+ MockBean bean = new MockBean();
+
+ PropUtils.setProperty(bean, "maximumInt", "10");
+ assertTrue("maximumInt equals 10", bean.getMaximumInt() == 10);
+
+ PropUtils.setProperty(bean, "maximumInt", "0");
+ assertTrue("maximumInt equals 0", bean.getMaximumInt() == 0);
+
+ PropUtils.setProperty(bean, "maximumInt", "$999.10");
+ assertTrue("maximumInt equals 999", bean.getMaximumInt() == 999);
+
+ PropUtils.setProperty(bean, "maximumInt",
+
"9999999999999999999999999999999999999999999999999.9999999999");
+ assertTrue("maximumInt equals Integer.MAX_VALUE",
+ bean.getMaximumInt() == Integer.MAX_VALUE);
+
+ }
+
+ /**
+ * <p>Tests setting a int property from a String</p>
+ */
+ public void testDouble() {
+ MockBean bean = new MockBean();
+
+ PropUtils.setProperty(bean, "maximumDouble", "10");
+ assertTrue("maximumDouble equals 10", bean.getMaximumDouble() == 10);
+
+ PropUtils.setProperty(bean, "maximumDouble", "$999.10", "$###.00");
+ assertTrue("maximumDouble equals $999.10",
+ bean.getMaximumDouble() == 999.10);
+
+
+ PropUtils.setProperty(bean, "maximumDouble", ".00001", ".#####");
+ assertTrue("maximumDouble equals .00001",
+ bean.getMaximumDouble() == .00001);
+
+ PropUtils
+ .setProperty(bean, "maximumDouble", "999,999.99",
"###,###.##");
+ assertTrue("maximumDouble equals 999,999.99,",
+ bean.getMaximumDouble() == 999999.99);
+
+ }
+
+ /**
+ * <p>Tests setting a String property from a String</p>
+ */
+ public void testString() {
+ MockBean bean = new MockBean();
+
+ PropUtils.setProperty(bean, "value", "#{managed-bean-name.value}");
+ assertTrue("value equals \"#{managed-bean-name.value}\"",
bean.getValue().equals("#{managed-bean-name.value}"));
+
+
+ }
+
+}
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]