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]