craigmcc    2003/02/03 23:28:14

  Modified:    beanutils/src/java/org/apache/commons/beanutils
                        BeanUtils.java
               beanutils/src/test/org/apache/commons/beanutils
                        BeanUtilsTestCase.java DynaBeanUtilsTestCase.java
  Log:
  Enhance BeanUtils.copyProperty() to deal with about 80% of the use cases for
  copying indexed, mapped, and nested properties with type conversions.  The
  remaining restrictions are documented in the Javadocs for this method.
  
  This is a partial response to Bugzilla #16525, which documents some
  restrictions in the functionality of copyProperty() that leads people
  to try setProperty() instead -- which they should not do.
  
  It is much more conservative than the proposed patch, which (as the reporter
  acknowledges) is more appropriate in a minor update (1.7) versus a bugfix
  patch (1.6.1) which is currently contemplated.
  
  PR: Bugzilla #16525
  Submitted by: Tim Vernum <tpv at spamcop.net>
  
  Revision  Changes    Path
  1.36      +147 -62   
jakarta-commons/beanutils/src/java/org/apache/commons/beanutils/BeanUtils.java
  
  Index: BeanUtils.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-commons/beanutils/src/java/org/apache/commons/beanutils/BeanUtils.java,v
  retrieving revision 1.35
  retrieving revision 1.36
  diff -u -r1.35 -r1.36
  --- BeanUtils.java    15 Jan 2003 21:59:38 -0000      1.35
  +++ BeanUtils.java    4 Feb 2003 07:28:14 -0000       1.36
  @@ -153,7 +153,7 @@
        * @exception InvocationTargetException if the property accessor method
        *  throws an exception
        * @exception NoSuchMethodException if an accessor method for this
  -     *  propety cannot be found
  +     *  property cannot be found
        */
       public static Object cloneBean(Object bean)
               throws IllegalAccessException, InstantiationException,
  @@ -275,18 +275,28 @@
       /**
        * <p>Copy the specified property value to the specified destination bean,
        * performing any type conversion that is required.  If the specified
  -     * bean does not have a property of the specified name, return without
  +     * bean does not have a property of the specified name, or the property
  +     * is read only on the destination bean, return without
        * doing anything.  If you have custom destination property types, register
        * {@link Converter}s for them by calling the <code>register()</code>
        * method of {@link ConvertUtils}.</p>
        *
  -     * <p><strong>FIXME</strong> - Indexed and mapped properties that do not
  -     * have getter and setter methods for the underlying array or Map are not
  -     * copied by this method.</p>
  +     * <p><strong>IMPLEMENTATION RESTRICTIONS</strong>:</p>
  +     * <ul>
  +     * <li>Does not support destination properties that are indexed,
  +     *     but only an indexed setter (as opposed to an array setter)
  +     *     is available.</li>
  +     * <li>Does not support destination properties that are mapped,
  +     *     but only a keyed setter (as opposed to a Map setter)
  +     *     is available.</li>
  +     * <li>The desired property type of a mapped setter cannot be
  +     *     determined (since Maps support any data type), so no conversion
  +     *     will be performed.</li>
  +     * </ul>
        *
        * @param bean Bean on which setting is to be performed
  -     * @param name Simple property name of the property to be set
  -     * @param value Property value to be set
  +     * @param name Property name (can be nested/indexed/mapped/combo)
  +     * @param value Value to be set
        *
        * @exception IllegalAccessException if the caller does not have
        *  access to the property accessor method
  @@ -296,6 +306,7 @@
       public static void copyProperty(Object bean, String name, Object value)
           throws IllegalAccessException, InvocationTargetException {
   
  +        // Trace logging (if enabled)
           if (log.isTraceEnabled()) {
               StringBuffer sb = new StringBuffer("  copyProperty(");
               sb.append(bean);
  @@ -323,55 +334,123 @@
               log.trace(sb.toString());
           }
   
  -        if (bean instanceof DynaBean) {
  -            DynaProperty propDescriptor =
  -                ((DynaBean) bean).getDynaClass().getDynaProperty(name);
  -            if (propDescriptor != null) {
  -                Converter converter =
  -                    ConvertUtils.lookup(propDescriptor.getType());
  -                if (converter != null) {
  -                    value = converter.convert(propDescriptor.getType(), value);
  -                }
  -                try {
  -                    PropertyUtils.setSimpleProperty(bean, name, value);
  -                } catch (NoSuchMethodException e) {
  -                    log.error("-->Should not have happened", e);
  -                    ; // Silently ignored
  +        // Resolve any nested expression to get the actual target bean
  +        Object target = bean;
  +        int delim = name.lastIndexOf(PropertyUtils.NESTED_DELIM);
  +        if (delim >= 0) {
  +            try {
  +                target =
  +                    PropertyUtils.getProperty(bean, name.substring(0, delim));
  +            } catch (NoSuchMethodException e) {
  +                return; // Skip this property setter
  +            }
  +            name = name.substring(delim + 1);
  +            if (log.isTraceEnabled()) {
  +                log.trace("    Target bean = " + target);
  +                log.trace("    Target name = " + name);
  +            }
  +        }
  +
  +        // Declare local variables we will require
  +        String propName = null;          // Simple name of target property
  +        Class type = null;               // Java type of target property
  +        int index = -1;                  // Indexed subscript value (if any)
  +        String key = null;               // Mapped key value (if any)
  +
  +        // Calculate the target property name, index, and key values
  +        propName = name;
  +        int i = propName.indexOf(PropertyUtils.INDEXED_DELIM);
  +        if (i >= 0) {
  +            int k = propName.indexOf(PropertyUtils.INDEXED_DELIM2);
  +            try {
  +                index =
  +                    Integer.parseInt(propName.substring(i + 1, k));
  +            } catch (NumberFormatException e) {
  +                ;
  +            }
  +            propName = propName.substring(0, i);
  +        }
  +        int j = propName.indexOf(PropertyUtils.MAPPED_DELIM);
  +        if (j >= 0) {
  +            int k = propName.indexOf(PropertyUtils.MAPPED_DELIM2);
  +            try {
  +                key = propName.substring(j + 1, k);
  +            } catch (IndexOutOfBoundsException e) {
  +                ;
  +            }
  +            propName = propName.substring(0, j);
  +        }
  +
  +        // Calculate the target property type
  +        if (target instanceof DynaBean) {
  +            DynaClass dynaClass = ((DynaBean) target).getDynaClass();
  +            DynaProperty dynaProperty = dynaClass.getDynaProperty(propName);
  +            if (dynaProperty == null) {
  +                return; // Skip this property setter
  +            }
  +            type = dynaProperty.getType();
  +        } else {
  +            PropertyDescriptor descriptor = null;
  +            try {
  +                descriptor =
  +                    PropertyUtils.getPropertyDescriptor(target, name);
  +                if (descriptor == null) {
  +                    return; // Skip this property setter
                   }
  -            } else {
  +            } catch (NoSuchMethodException e) {
  +                return; // Skip this property setter
  +            }
  +            type = descriptor.getPropertyType();
  +            if (type == null) {
  +                // Most likely an indexed setter on a POJB only
                   if (log.isTraceEnabled()) {
  -                    log.trace("-->No setter on 'to' DynaBean, skipping");
  +                    log.trace("    target type for property '" +
  +                              propName + "' is null, so skipping ths setter");
                   }
  +                return;
  +            }
  +        }
  +        if (log.isTraceEnabled()) {
  +            log.trace("    target propName=" + propName + ", type=" +
  +                      type + ", index=" + index + ", key=" + key);
  +        }
  +
  +        // Convert the specified value to the required type and store it
  +        if (index >= 0) {                    // Destination must be indexed
  +            Converter converter = ConvertUtils.lookup(type.getComponentType());
  +            if (converter != null) {
  +                log.trace("        USING CONVERTER " + converter);
  +                value = converter.convert(type, value);
               }
  -        } else /* if (!(bean instanceof DynaBean)) */ {
  -            PropertyDescriptor propDescriptor = null;
               try {
  -                propDescriptor =
  -                    PropertyUtils.getPropertyDescriptor(bean, name);
  +                PropertyUtils.setIndexedProperty(target, propName,
  +                                                 index, value);
               } catch (NoSuchMethodException e) {
  -                propDescriptor = null;
  +                throw new InvocationTargetException
  +                    (e, "Cannot set " + propName);
               }
  -            if ((propDescriptor != null) &&
  -                (propDescriptor.getWriteMethod() == null)) {
  -                propDescriptor = null;
  -            }
  -            if (propDescriptor != null) {
  -                Converter converter =
  -                    ConvertUtils.lookup(propDescriptor.getPropertyType());
  -                if (converter != null) {
  -                    value = converter.convert
  -                        (propDescriptor.getPropertyType(), value);
  -                }
  -                try {
  -                    PropertyUtils.setSimpleProperty(bean, name, value);
  -                } catch (NoSuchMethodException e) {
  -                    log.error("-->Should not have happened", e);
  -                    ; // Silently ignored
  -                }
  -            } else {
  -                if (log.isTraceEnabled()) {
  -                    log.trace("-->No setter on JavaBean, skipping");
  -                }
  +        } else if (key != null) {            // Destination must be mapped
  +            // Maps do not know what the preferred data type is,
  +            // so perform no conversions at all
  +            // FIXME - should we create or support a TypedMap?
  +            try {
  +                PropertyUtils.setMappedProperty(target, propName,
  +                                                key, value);
  +            } catch (NoSuchMethodException e) {
  +                throw new InvocationTargetException
  +                    (e, "Cannot set " + propName);
  +            }
  +        } else {                             // Destination must be simple
  +            Converter converter = ConvertUtils.lookup(type);
  +            if (converter != null) {
  +                log.trace("        USING CONVERTER " + converter);
  +                value = converter.convert(type, value);
  +            }
  +            try {
  +                PropertyUtils.setSimpleProperty(target, propName, value);
  +            } catch (NoSuchMethodException e) {
  +                throw new InvocationTargetException
  +                    (e, "Cannot set " + propName);
               }
           }
   
  @@ -392,7 +471,7 @@
        * @exception InvocationTargetException if the property accessor method
        *  throws an exception
        * @exception NoSuchMethodException if an accessor method for this
  -     *  propety cannot be found
  +     *  property cannot be found
        */
       public static Map describe(Object bean)
               throws IllegalAccessException, InvocationTargetException,
  @@ -441,7 +520,7 @@
        * @exception InvocationTargetException if the property accessor method
        *  throws an exception
        * @exception NoSuchMethodException if an accessor method for this
  -     *  propety cannot be found
  +     *  property cannot be found
        */
       public static String[] getArrayProperty(Object bean, String name)
               throws IllegalAccessException, InvocationTargetException,
  @@ -499,7 +578,7 @@
        * @exception InvocationTargetException if the property accessor method
        *  throws an exception
        * @exception NoSuchMethodException if an accessor method for this
  -     *  propety cannot be found
  +     *  property cannot be found
        */
       public static String getIndexedProperty(Object bean, String name)
               throws IllegalAccessException, InvocationTargetException,
  @@ -525,7 +604,7 @@
        * @exception InvocationTargetException if the property accessor method
        *  throws an exception
        * @exception NoSuchMethodException if an accessor method for this
  -     *  propety cannot be found
  +     *  property cannot be found
        */
       public static String getIndexedProperty(Object bean,
                                               String name, int index)
  @@ -554,7 +633,7 @@
        * @exception InvocationTargetException if the property accessor method
        *  throws an exception
        * @exception NoSuchMethodException if an accessor method for this
  -     *  propety cannot be found
  +     *  property cannot be found
        */
       public static String getMappedProperty(Object bean, String name)
               throws IllegalAccessException, InvocationTargetException,
  @@ -580,7 +659,7 @@
        * @exception InvocationTargetException if the property accessor method
        *  throws an exception
        * @exception NoSuchMethodException if an accessor method for this
  -     *  propety cannot be found
  +     *  property cannot be found
        */
       public static String getMappedProperty(Object bean,
                                              String name, String key)
  @@ -607,7 +686,7 @@
        * @exception InvocationTargetException if the property accessor method
        *  throws an exception
        * @exception NoSuchMethodException if an accessor method for this
  -     *  propety cannot be found
  +     *  property cannot be found
        */
       public static String getNestedProperty(Object bean, String name)
               throws IllegalAccessException, InvocationTargetException,
  @@ -632,7 +711,7 @@
        * @exception InvocationTargetException if the property accessor method
        *  throws an exception
        * @exception NoSuchMethodException if an accessor method for this
  -     *  propety cannot be found
  +     *  property cannot be found
        */
       public static String getProperty(Object bean, String name)
               throws IllegalAccessException, InvocationTargetException,
  @@ -655,7 +734,7 @@
        * @exception InvocationTargetException if the property accessor method
        *  throws an exception
        * @exception NoSuchMethodException if an accessor method for this
  -     *  propety cannot be found
  +     *  property cannot be found
        */
       public static String getSimpleProperty(Object bean, String name)
               throws IllegalAccessException, InvocationTargetException,
  @@ -747,6 +826,12 @@
        * to meet the needs of <code>populate()</code>, and is probably not what
        * you want for general property copying with type conversion.  For that
        * purpose, check out the <code>copyProperty()</code> method instead.</p>
  +     *
  +     * <p><strong>WARNING</strong> - PLEASE do not modify the behavior of this
  +     * method without consulting with the Struts developer community.  There
  +     * are some subtleties to its functionality that are not documented in the
  +     * Javadoc description above, yet are vital to the way that Struts utilizes
  +     * this method.</p>
        *
        * @param bean Bean on which setting is to be performed
        * @param name Property name (can be nested/indexed/mapped/combo)
  
  
  
  1.20      +125 -4    
jakarta-commons/beanutils/src/test/org/apache/commons/beanutils/BeanUtilsTestCase.java
  
  Index: BeanUtilsTestCase.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-commons/beanutils/src/test/org/apache/commons/beanutils/BeanUtilsTestCase.java,v
  retrieving revision 1.19
  retrieving revision 1.20
  diff -u -r1.19 -r1.20
  --- BeanUtilsTestCase.java    1 Feb 2003 08:14:33 -0000       1.19
  +++ BeanUtilsTestCase.java    4 Feb 2003 07:28:14 -0000       1.20
  @@ -64,6 +64,7 @@
   
   import java.lang.reflect.InvocationTargetException;
   import java.util.HashMap;
  +import java.util.Iterator;
   import java.util.Map;
   
   import junit.framework.Test;
  @@ -1112,6 +1113,126 @@
           BeanUtils.copyProperty(bean, "shortProperty", new Short((short) 123));
           assertEquals((short) 123, bean.getShortProperty());
   
  +    }
  +
  +
  +    /**
  +     * Test copying a property using a nested indexed array expression,
  +     * with and without conversions.
  +     */
  +    public void testCopyPropertyNestedIndexedArray() throws Exception {
  +
  +        int origArray[] = { 0, 10, 20, 30, 40 };
  +        int intArray[] = { 0, 0, 0 };
  +        bean.getNested().setIntArray(intArray);
  +        int intChanged[] = { 0, 0, 0 };
  +
  +        // No conversion required
  +        BeanUtils.copyProperty(bean, "nested.intArray[1]", new Integer(1));
  +        checkIntArray(bean.getIntArray(), origArray);
  +        intChanged[1] = 1;
  +        checkIntArray(bean.getNested().getIntArray(), intChanged);
  +
  +        // Widening conversion required
  +        BeanUtils.copyProperty(bean, "nested.intArray[1]", new Byte((byte) 2));
  +        checkIntArray(bean.getIntArray(), origArray);
  +        intChanged[1] = 2;
  +        checkIntArray(bean.getNested().getIntArray(), intChanged);
  +
  +        // Narrowing conversion required
  +        BeanUtils.copyProperty(bean, "nested.intArray[1]", new Long((long) 3));
  +        checkIntArray(bean.getIntArray(), origArray);
  +        intChanged[1] = 3;
  +        checkIntArray(bean.getNested().getIntArray(), intChanged);
  +
  +        // String conversion required
  +        BeanUtils.copyProperty(bean, "nested.intArray[1]", "4");
  +        checkIntArray(bean.getIntArray(), origArray);
  +        intChanged[1] = 4;
  +        checkIntArray(bean.getNested().getIntArray(), intChanged);
  +
  +    }
  +
  +
  +    /**
  +     * Test copying a property using a nested mapped map property.
  +     */
  +    public void testCopyPropertyNestedMappedMap() throws Exception {
  +
  +        Map origMap = new HashMap();
  +        origMap.put("First Key", "First Value");
  +        origMap.put("Second Key", "Second Value");
  +        Map changedMap = new HashMap();
  +        changedMap.put("First Key", "First Value");
  +        changedMap.put("Second Key", "Second Value");
  +
  +        // No conversion required
  +        BeanUtils.copyProperty(bean, "nested.mapProperty(Second Key)",
  +                               "New Second Value");
  +        checkMap(bean.getMapProperty(), origMap);
  +        changedMap.put("Second Key", "New Second Value");
  +        checkMap(bean.getNested().getMapProperty(), changedMap);
  +
  +    }
  +
  +
  +    /**
  +     * Test copying a property using a nested simple expression, with and
  +     * without conversions.
  +     */
  +    public void testCopyPropertyNestedSimple() throws Exception {
  +
  +        bean.setIntProperty(0);
  +        bean.getNested().setIntProperty(0);
  +
  +        // No conversion required
  +        BeanUtils.copyProperty(bean, "nested.intProperty", new Integer(1));
  +        assertNotNull(bean.getNested());
  +        assertEquals(0, bean.getIntProperty());
  +        assertEquals(1, bean.getNested().getIntProperty());
  +
  +        // Widening conversion required
  +        BeanUtils.copyProperty(bean, "nested.intProperty", new Byte((byte) 2));
  +        assertNotNull(bean.getNested());
  +        assertEquals(0, bean.getIntProperty());
  +        assertEquals(2, bean.getNested().getIntProperty());
  +
  +        // Narrowing conversion required
  +        BeanUtils.copyProperty(bean, "nested.intProperty", new Long((long) 3));
  +        assertNotNull(bean.getNested());
  +        assertEquals(0, bean.getIntProperty());
  +        assertEquals(3, bean.getNested().getIntProperty());
  +
  +        // String conversion required
  +        BeanUtils.copyProperty(bean, "nested.intProperty", "4");
  +        assertNotNull(bean.getNested());
  +        assertEquals(0, bean.getIntProperty());
  +        assertEquals(4, bean.getNested().getIntProperty());
  +
  +    }
  +
  +
  +    // Ensure that the actual int[] matches the expected int[]
  +    protected void checkIntArray(int actual[], int expected[]) {
  +        assertNotNull("actual array not null", actual);
  +        assertEquals("actual array length", expected.length, actual.length);
  +        for (int i = 0; i < actual.length; i++) {
  +            assertEquals("actual array value[" + i + "]",
  +                         expected[i], actual[i]);
  +        }
  +    }
  +
  +
  +    // Ensure that the actual Map matches the expected Map
  +    protected void checkMap(Map actual, Map expected) {
  +        assertNotNull("actual map not null", actual);
  +        assertEquals("actual map size", expected.size(), actual.size());
  +        Iterator keys = expected.keySet().iterator();
  +        while (keys.hasNext()) {
  +            Object key = keys.next();
  +            assertEquals("actual map value(" + key + ")",
  +                         expected.get(key), actual.get(key));
  +        }
       }
   
   
  
  
  
  1.17      +131 -4    
jakarta-commons/beanutils/src/test/org/apache/commons/beanutils/DynaBeanUtilsTestCase.java
  
  Index: DynaBeanUtilsTestCase.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-commons/beanutils/src/test/org/apache/commons/beanutils/DynaBeanUtilsTestCase.java,v
  retrieving revision 1.16
  retrieving revision 1.17
  diff -u -r1.16 -r1.17
  --- DynaBeanUtilsTestCase.java        1 Feb 2003 08:14:33 -0000       1.16
  +++ DynaBeanUtilsTestCase.java        4 Feb 2003 07:28:14 -0000       1.17
  @@ -65,6 +65,7 @@
   import java.lang.reflect.InvocationTargetException;
   import java.util.ArrayList;
   import java.util.HashMap;
  +import java.util.Iterator;
   import java.util.List;
   import java.util.Map;
   
  @@ -113,6 +114,7 @@
         "intProperty",
         "listIndexed",
         "longProperty",
  +      "mapProperty",
         "mappedProperty",
         "mappedIntProperty",
         "nested",
  @@ -173,6 +175,10 @@
           listIndexed.add("String 4");
           bean.set("listIndexed", listIndexed);
           bean.set("longProperty", new Long((long) 321));
  +        HashMap mapProperty = new HashMap();
  +        mapProperty.put("First Key", "First Value");
  +        mapProperty.put("Second Key", "Second Value");
  +        bean.set("mapProperty", mapProperty);
           HashMap mappedProperty = new HashMap();
           mappedProperty.put("First Key", "First Value");
           mappedProperty.put("Second Key", "Second Value");
  @@ -1037,9 +1043,129 @@
       }
   
   
  +    /**
  +     * Test copying a property using a nested indexed array expression,
  +     * with and without conversions.
  +     */
  +    public void testCopyPropertyNestedIndexedArray() throws Exception {
  +
  +        int origArray[] = { 0, 10, 20, 30, 40};
  +        int intArray[] = { 0, 0, 0 };
  +        ((TestBean) bean.get("nested")).setIntArray(intArray);
  +        int intChanged[] = { 0, 0, 0 };
  +
  +        // No conversion required
  +        BeanUtils.copyProperty(bean, "nested.intArray[1]", new Integer(1));
  +        checkIntArray((int[]) bean.get("intArray"), origArray);
  +        intChanged[1] = 1;
  +        checkIntArray(((TestBean) bean.get("nested")).getIntArray(),
  +                      intChanged);
  +
  +        // Widening conversion required
  +        BeanUtils.copyProperty(bean, "nested.intArray[1]", new Byte((byte) 2));
  +        checkIntArray((int[]) bean.get("intArray"), origArray);
  +        intChanged[1] = 2;
  +        checkIntArray(((TestBean) bean.get("nested")).getIntArray(),
  +                      intChanged);
  +
  +        // Narrowing conversion required
  +        BeanUtils.copyProperty(bean, "nested.intArray[1]", new Long((long) 3));
  +        checkIntArray((int[]) bean.get("intArray"), origArray);
  +        intChanged[1] = 3;
  +        checkIntArray(((TestBean) bean.get("nested")).getIntArray(),
  +                      intChanged);
  +
  +        // String conversion required
  +        BeanUtils.copyProperty(bean, "nested.intArray[1]", "4");
  +        checkIntArray((int[]) bean.get("intArray"), origArray);
  +        intChanged[1] = 4;
  +        checkIntArray(((TestBean) bean.get("nested")).getIntArray(),
  +                      intChanged);
  +
  +    }
  +
  +
  +    /**
  +     * Test copying a property using a nested mapped map property.
  +     */
  +    public void testCopyPropertyNestedMappedMap() throws Exception {
  +
  +        Map origMap = new HashMap();
  +        origMap.put("First Key", "First Value");
  +        origMap.put("Second Key", "Second Value");
  +        Map changedMap = new HashMap();
  +        changedMap.put("First Key", "First Value");
  +        changedMap.put("Second Key", "Second Value");
  +
  +        // No conversion required
  +        BeanUtils.copyProperty(bean, "nested.mapProperty(Second Key)",
  +                               "New Second Value");
  +        checkMap((Map) bean.get("mapProperty"), origMap);
  +        changedMap.put("Second Key", "New Second Value");
  +        checkMap(((TestBean) bean.get("nested")).getMapProperty(), changedMap);
  +
  +    }
  +
  +
  +    /**
  +     * Test copying a property using a nested simple expression, with and
  +     * without conversions.
  +     */
  +    public void testCopyPropertyNestedSimple() throws Exception {
  +
  +        bean.set("intProperty", new Integer(0));
  +        nested.setIntProperty(0);
  +
  +        // No conversion required
  +        BeanUtils.copyProperty(bean, "nested.intProperty", new Integer(1));
  +        assertEquals(0, ((Integer) bean.get("intProperty")).intValue());
  +        assertEquals(1, nested.getIntProperty());
  +
  +        // Widening conversion required
  +        BeanUtils.copyProperty(bean, "nested.intProperty", new Byte((byte) 2));
  +        assertEquals(0, ((Integer) bean.get("intProperty")).intValue());
  +        assertEquals(2, nested.getIntProperty());
  +
  +        // Narrowing conversion required
  +        BeanUtils.copyProperty(bean, "nested.intProperty", new Long((long) 3));
  +        assertEquals(0, ((Integer) bean.get("intProperty")).intValue());
  +        assertEquals(3, nested.getIntProperty());
  +
  +        // String conversion required
  +        BeanUtils.copyProperty(bean, "nested.intProperty", "4");
  +        assertEquals(0, ((Integer) bean.get("intProperty")).intValue());
  +        assertEquals(4, nested.getIntProperty());
  +
  +    }
  +
  +
       // ------------------------------------------------------ Protected Methods
   
   
  +    // Ensure that the nested intArray matches the specified values
  +    protected void checkIntArray(int actual[], int expected[]) {
  +        assertNotNull("actual array not null", actual);
  +        assertEquals("actual array length", expected.length, actual.length);
  +        for (int i = 0; i < actual.length; i++) {
  +            assertEquals("actual array value[" + i + "]",
  +                         expected[i], actual[i]);
  +        }
  +    }
  +
  +
  +    // Ensure that the actual Map matches the expected Map
  +    protected void checkMap(Map actual, Map expected) {
  +        assertNotNull("actual map not null", actual);
  +        assertEquals("actual map size", expected.size(), actual.size());
  +        Iterator keys = expected.keySet().iterator();
  +        while (keys.hasNext()) {
  +            Object key = keys.next();
  +            assertEquals("actual map value(" + key + ")",
  +                         expected.get(key), actual.get(key));
  +        }
  +    }
  +
  +
       /**
        * Create and return a <code>DynaClass</code> instance for our test
        * <code>DynaBean</code>.
  @@ -1063,6 +1189,7 @@
                               new DynaProperty("intProperty", Integer.TYPE),
                               new DynaProperty("listIndexed", List.class),
                               new DynaProperty("longProperty", Long.TYPE),
  +                            new DynaProperty("mapProperty", Map.class),
                               new DynaProperty("mappedProperty", Map.class),
                               new DynaProperty("mappedIntProperty", Map.class),
                               new DynaProperty("nested", TestBean.class),
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to