You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by ni...@apache.org on 2004/07/16 14:31:43 UTC

cvs commit: jakarta-commons/beanutils/src/java/org/apache/commons/beanutils LazyDynaMap.java LazyDynaClass.java LazyDynaBean.java

niallp      2004/07/16 05:31:43

  Modified:    beanutils/src/java/org/apache/commons/beanutils
                        LazyDynaClass.java LazyDynaBean.java
  Added:       beanutils/src/java/org/apache/commons/beanutils
                        LazyDynaMap.java
  Log:
  Refactor LazyDynaBean and add new LazyDynaMap class
  
  Revision  Changes    Path
  1.2       +32 -15    jakarta-commons/beanutils/src/java/org/apache/commons/beanutils/LazyDynaClass.java
  
  Index: LazyDynaClass.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/beanutils/src/java/org/apache/commons/beanutils/LazyDynaClass.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- LazyDynaClass.java	5 Jul 2004 00:48:12 -0000	1.1
  +++ LazyDynaClass.java	16 Jul 2004 12:31:43 -0000	1.2
  @@ -1,5 +1,5 @@
   /*
  - * Copyright 2001-2004 The Apache Software Foundation.
  + * Copyright 2004 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.
  @@ -39,7 +39,6 @@
    *    in order to control read/write facilities.</p>
    *
    * @see LazyDynaBean
  - * @see MutableDynaClass
    * @author Niall Pemberton
    */
   public class LazyDynaClass extends BasicDynaClass implements MutableDynaClass  {
  @@ -61,7 +60,7 @@
        * Construct a new LazyDynaClass with default parameters.
        */
       public LazyDynaClass() {
  -        super(null, LazyDynaBean.class);
  +        this(null, (DynaProperty[])null);
       }
   
       /**
  @@ -71,7 +70,7 @@
        * @param dynaBeanClass The implementation class for new instances
        */
       public LazyDynaClass(String name) {
  -        super(name, LazyDynaBean.class);
  +        this(name, (DynaProperty[])null);
       }
   
       /**
  @@ -81,7 +80,7 @@
        * @param dynaBeanClass The implementation class for new instances
        */
       public LazyDynaClass(String name, Class dynaBeanClass) {
  -        super(name, dynaBeanClass);
  +        this(name, dynaBeanClass, null);
       }
   
       /**
  @@ -91,8 +90,18 @@
        * @param dynaBeanClass The implementation class for new intances
        * @param properties Property descriptors for the supported properties
        */
  -    public LazyDynaClass(String name, Class dynaBeanClass,
  -                          DynaProperty properties[]) {
  +    public LazyDynaClass(String name, DynaProperty[] properties) {
  +        this(name, LazyDynaBean.class, properties);
  +    }
  +
  +    /**
  +     * Construct a new LazyDynaClass with the specified parameters.
  +     *
  +     * @param name Name of this DynaBean class
  +     * @param dynaBeanClass The implementation class for new intances
  +     * @param properties Property descriptors for the supported properties
  +     */
  +    public LazyDynaClass(String name, Class dynaBeanClass, DynaProperty properties[]) {
           super(name, dynaBeanClass, properties);
       }
   
  @@ -199,15 +208,18 @@
        */
       protected void add(DynaProperty property) {
   
  -        if (property.getName() == null)
  +        if (property.getName() == null) {
               throw new IllegalArgumentException("Property name is missing.");
  +        }
   
  -        if (isRestricted())
  +        if (isRestricted()) {
               throw new IllegalStateException("DynaClass is currently restricted. No new properties can be added.");
  +        }
   
           // Check if property already exists
  -        if (propertiesMap.get(name) != null)
  +        if (propertiesMap.get(name) != null) {
              return;
  +        }
   
           // Create a new property array with the specified property
           DynaProperty[] oldProperties = getDynaProperties();
  @@ -235,15 +247,18 @@
        */
       public void remove(String name) {
   
  -        if (name == null)
  +        if (name == null) {
               throw new IllegalArgumentException("Property name is missing.");
  +        }
   
  -        if (isRestricted())
  +        if (isRestricted()) {
               throw new IllegalStateException("DynaClass is currently restricted. No properties can be removed.");
  +        }
   
           // Ignore if property doesn't exist
  -        if (propertiesMap.get(name) == null)
  +        if (propertiesMap.get(name) == null) {
               return;
  +        }
   
   
           // Create a new property array of without the specified property
  @@ -286,8 +301,9 @@
        */
       public DynaProperty getDynaProperty(String name) {
   
  -        if (name == null)
  +        if (name == null) {
               throw new IllegalArgumentException("Property name is missing.");
  +        }
   
           DynaProperty dynaProperty = (DynaProperty)propertiesMap.get(name);
   
  @@ -313,8 +329,9 @@
        */
       public boolean isDynaProperty(String name) {
   
  -        if (name == null)
  +        if (name == null) {
               throw new IllegalArgumentException("Property name is missing.");
  +        }
   
           return propertiesMap.get(name) ==  null ? false : true;
   
  
  
  
  1.2       +511 -117  jakarta-commons/beanutils/src/java/org/apache/commons/beanutils/LazyDynaBean.java
  
  Index: LazyDynaBean.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/beanutils/src/java/org/apache/commons/beanutils/LazyDynaBean.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- LazyDynaBean.java	5 Jul 2004 00:48:12 -0000	1.1
  +++ LazyDynaBean.java	16 Jul 2004 12:31:43 -0000	1.2
  @@ -1,5 +1,5 @@
   /*
  - * Copyright 2001-2004 The Apache Software Foundation.
  + * Copyright 2004 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.
  @@ -19,15 +19,16 @@
   import java.util.ArrayList;
   import java.util.Map;
   import java.util.HashMap;
  +import java.util.Date;
   import java.lang.reflect.Array;
  +import java.math.BigDecimal;
  +import java.math.BigInteger;
  +import org.apache.commons.logging.Log;
  +import org.apache.commons.logging.LogFactory;
   
   /**
    * <p>DynaBean which automatically adds properties to the <code>DynaClass</code>
  - * if they don't exist.</p>
  - *
  - * <p><strong>N.B.</strong> Must be used with a <code>DynaClass</code> that
  - * implements the <code>MutableDynaClass</code> interface - if not specified
  - * the <code>LazyDynaClass</code> is used by default.</p>
  + *   and provides <i>Lazy List</i> and <i>Lazy Map</i> features.</p>
    *
    * <p>DynaBeans deal with three types of properties - <i>simple</i>, <i>indexed</i> and <i>mapped</i> and
    *    have the following <code>get()</code> and <code>set()</code> methods for
  @@ -104,21 +105,44 @@
    * @see LazyDynaClass
    * @author Niall Pemberton
    */
  -public class LazyDynaBean extends BasicDynaBean {
  +public class LazyDynaBean implements DynaBean  {
  +
  +
  +   /**
  +    * Commons Logging
  +    */
  +    private static Log logger = LogFactory.getLog(LazyDynaBean.class);
  +
  +    protected static final BigInteger BigInteger_ZERO = new BigInteger("0");
  +    protected static final BigDecimal BigDecimal_ZERO = new BigDecimal("0");
  +    protected static final Character  Character_SPACE = new Character(' ');
  +    protected static final Byte       Byte_ZERO       = new Byte((byte)0);
  +    protected static final Short      Short_ZERO      = new Short((short)0);
  +    protected static final Integer    Integer_ZERO    = new Integer(0);
  +    protected static final Long       Long_ZERO       = new Long((long)0);
  +    protected static final Float      Float_ZERO      = new Float((byte)0);
  +    protected static final Double     Double_ZERO     = new Double((byte)0);
   
       /**
        * The <code>MutableDynaClass</code> "base class" that this DynaBean
        * is associated with.
        */
  -    protected MutableDynaClass mutableDynaClass;
  +    protected Map values;
  +
  +    /**
  +     * The <code>MutableDynaClass</code> "base class" that this DynaBean
  +     * is associated with.
  +     */
  +    protected MutableDynaClass dynaClass;
  +
  +
  +    // ------------------- Constructors ----------------------------------
   
       /**
        * Construct a new <code>LazyDynaBean</code> with a <code>LazyDynaClass</code> instance.
        */
       public LazyDynaBean() {
  -
           this(new LazyDynaClass());
  -
       }
   
       /**
  @@ -127,26 +151,98 @@
        * @param name Name of this DynaBean class
        */
       public LazyDynaBean(String name) {
  -
           this(new LazyDynaClass(name));
  -
       }
   
       /**
        * Construct a new <code>DynaBean</code> associated with the specified
  -     * <code>DynaClass</code> instance - must be <code>MutableDynaClass</code>.
  +     * <code>DynaClass</code> instance - if its not a <code>MutableDynaClass</code>
  +     * then a new <code>LazyDynaClass</code> is created and the properties copied.
        *
        * @param dynaClass The DynaClass we are associated with
        */
       public LazyDynaBean(DynaClass dynaClass) {
   
  -        super(dynaClass);
  +        values = newMap();
  +
  +        if (dynaClass instanceof MutableDynaClass) {
  +            this.dynaClass = (MutableDynaClass)dynaClass;
  +        } else {
  +            this.dynaClass = new LazyDynaClass(dynaClass.getName(), dynaClass.getDynaProperties());
  +        }
  +
  +    }
   
  -        if (!(dynaClass instanceof MutableDynaClass))
  -            throw new IllegalArgumentException("DynaClass must be a MutableDynaClass type: " +
  -                                                dynaClass.getClass().getName());
   
  -        mutableDynaClass = (MutableDynaClass)dynaClass;
  +    // ------------------- Public Methods ----------------------------------
  +
  +    /**
  +     * Return the Map backing this <code>DynaBean</code>
  +     */
  +    public Map getMap() {
  +        return values;
  +    }
  +
  +    /**
  +     * <p>Return the size of an indexed or mapped property.</p>
  +     *
  +     * @param size Size of the Map, List or Array.
  +     * @exception IllegalArgumentException if no property name is specified
  +     */
  +    public int size(String name) {
  +
  +        if (name == null) {
  +            throw new IllegalArgumentException("No property name specified");
  +        }
  +
  +        Object value = values.get(name);
  +        if (value == null) {
  +            return 0;
  +        }
  +
  +        if (value instanceof Map) {
  +            return ((Map)value).size();
  +        }
  +
  +        if (value instanceof List) {
  +            return ((List)value).size();
  +        }
  +
  +        if ((value.getClass().isArray())) {
  +            return Array.getLength(value);
  +        }
  +
  +        return 0;
  +
  +    }
  +
  +    // ------------------- DynaBean Methods ----------------------------------
  +
  +    /**
  +     * Does the specified mapped property contain a value for the specified
  +     * key value?
  +     *
  +     * @param name Name of the property to check
  +     * @param key Name of the key to check
  +     *
  +     * @exception IllegalArgumentException if no property name is specified
  +     */
  +    public boolean contains(String name, String key) {
  +
  +        if (name == null) {
  +            throw new IllegalArgumentException("No property name specified");
  +        }
  +
  +        Object value = values.get(name);
  +        if (value == null) {
  +            return false;
  +        }
  +
  +        if (value instanceof Map) {
  +            return (((Map) value).containsKey(key));
  +        }
  +
  +        return false;
   
       }
   
  @@ -157,19 +253,34 @@
        *  of the specified name.</p>
        *
        * @param name Name of the property whose value is to be retrieved.
  +     * @exception IllegalArgumentException if no property name is specified
        */
       public Object get(String name) {
   
  -        if (isDynaProperty(name)) {
  -
  -            return super.get(name);
  +        if (name == null) {
  +            throw new IllegalArgumentException("No property name specified");
  +        }
   
  -        } else {
  +        // Value found
  +        Object value = values.get(name);
  +        if (value != null) {
  +            return value;
  +        }
   
  +        // Property doesn't exist
  +        if (!isDynaProperty(name)) {
               return null;
  +        }
   
  +        // Property doesn't exist
  +        value = createProperty(name, dynaClass.getDynaProperty(name).getType());
  +
  +        if (value != null) {
  +            set(name, value);
           }
   
  +        return value;
  +
       }
   
       /**
  @@ -188,14 +299,33 @@
        */
       public Object get(String name, int index) {
   
  -        if (get(name) == null) {
  +        // If its not a property, then create default indexed property
  +        if (!isDynaProperty(name)) {
  +            set(name, defaultIndexedProperty(name));
  +        }
   
  -            return null;
  +        // Get the indexed property
  +        Object indexedProperty = get(name);
   
  -        } else {
  +        // Check that the property is indexed
  +        if (!dynaClass.getDynaProperty(name).isIndexed()) {
  +            throw new IllegalArgumentException
  +                ("Non-indexed property for '" + name + "[" + index + "]' "
  +                                      + dynaClass.getDynaProperty(name).getName());
  +        }
   
  -            return super.get(name, index);
  +        // Grow indexed property to appropriate size
  +        indexedProperty = growIndexedProperty(name, indexedProperty, index);
   
  +        // Return the indexed value
  +        if (indexedProperty.getClass().isArray()) {
  +            return Array.get(indexedProperty, index);
  +        } else if (indexedProperty instanceof List) {
  +            return ((List)indexedProperty).get(index);
  +        } else {
  +            throw new IllegalArgumentException
  +                ("Non-indexed property for '" + name + "[" + index + "]' "
  +                                  + indexedProperty.getClass().getName());
           }
   
       }
  @@ -214,14 +344,69 @@
        */
       public Object get(String name, String key) {
   
  -        if (get(name) == null) {
  +        // If its not a property, then create default mapped property
  +        if (!isDynaProperty(name)) {
  +            set(name, defaultMappedProperty(name));
  +        }
   
  -            return null;
  +        // Get the mapped property
  +        Object mappedProperty = get(name);
   
  +        // Check that the property is mapped
  +        if (!dynaClass.getDynaProperty(name).isMapped()) {
  +            throw new IllegalArgumentException
  +                ("Non-mapped property for '" + name + "(" + key + ")'"
  +                            + dynaClass.getDynaProperty(name).getType().getName());
  +        }
  +
  +        // Get the value from the Map
  +        if (mappedProperty instanceof Map) {
  +            return (((Map) mappedProperty).get(key));
           } else {
  +            throw new IllegalArgumentException
  +              ("Non-mapped property for '" + name + "(" + key + ")'"
  +                                  + mappedProperty.getClass().getName());
  +        }
  +
  +    }
  +
   
  -            return super.get(name, key);
  +    /**
  +     * Return the <code>DynaClass</code> instance that describes the set of
  +     * properties available for this DynaBean.
  +     */
  +    public DynaClass getDynaClass() {
  +        return (DynaClass)dynaClass;
  +    }
   
  +    /**
  +     * Remove any existing value for the specified key on the
  +     * specified mapped property.
  +     *
  +     * @param name Name of the property for which a value is to
  +     *  be removed
  +     * @param key Key of the value to be removed
  +     *
  +     * @exception IllegalArgumentException if there is no property
  +     *  of the specified name
  +     */
  +    public void remove(String name, String key) {
  +
  +        if (name == null) {
  +            throw new IllegalArgumentException("No property name specified");
  +        }
  +
  +        Object value = values.get(name);
  +        if (value == null) {
  +            return;
  +        }
  +
  +        if (value instanceof Map) {
  +            ((Map) value).remove(key);
  +        } else {
  +            throw new IllegalArgumentException
  +                    ("Non-mapped property for '" + name + "(" + key + ")'"
  +                            + value.getClass().getName());
           }
   
       }
  @@ -244,21 +429,35 @@
           // If the property doesn't exist, then add it
           if (!isDynaProperty(name)) {
   
  -            if (mutableDynaClass.isRestricted()) {
  +            if (dynaClass.isRestricted()) {
                   throw new IllegalArgumentException
                       ("Invalid property name '" + name + "' (DynaClass is restricted)");
               }
  -
               if (value == null) {
  -                mutableDynaClass.add(name);
  +                dynaClass.add(name);
               } else {
  -                mutableDynaClass.add(name, value.getClass());
  +                dynaClass.add(name, value.getClass());
               }
   
           }
   
  +        DynaProperty descriptor = dynaClass.getDynaProperty(name);
  +
  +        if (value == null) {
  +            if (descriptor.getType().isPrimitive()) {
  +                throw new NullPointerException
  +                        ("Primitive value for '" + name + "'");
  +            }
  +        } else if (!isAssignable(descriptor.getType(), value.getClass())) {
  +            throw new ConversionException
  +                    ("Cannot assign value of type '" +
  +                    value.getClass().getName() +
  +                    "' to property '" + name + "' of type '" +
  +                    descriptor.getType().getName() + "'");
  +        }
  +
           // Set the property's value
  -        super.set(name, value);
  +        values.put(name, value);
   
       }
   
  @@ -280,132 +479,294 @@
        */
       public void set(String name, int index, Object value) {
   
  -        // If the 'indexed' property doesn't exist, then add it
  +        // If its not a property, then create default indexed property
           if (!isDynaProperty(name)) {
  -            set(name, newIndexedProperty(name));
  +            set(name, defaultIndexedProperty(name));
           }
   
  -        // Check if its an Indexed Property
  -        DynaProperty dynaProperty = mutableDynaClass.getDynaProperty(name);
  -        if (!dynaProperty.isIndexed()) {
  +        // Get the indexed property
  +        Object indexedProperty = get(name);
  +
  +        // Check that the property is indexed
  +        if (!dynaClass.getDynaProperty(name).isIndexed()) {
               throw new IllegalArgumentException
  -                    ("Non-indexed property for '" + name + "[" + index + "]', type is '" +
  -                         dynaProperty.getType().getName()+"'");
  +                ("Non-indexed property for '" + name + "[" + index + "]'"
  +                            + dynaClass.getDynaProperty(name).getType().getName());
           }
   
  +        // Grow indexed property to appropriate size
  +        indexedProperty = growIndexedProperty(name, indexedProperty, index);
   
  -        // Instantiate the indexed property
  -        Object prop = get(name);
  -        if (prop == null) {
  -            Class type = dynaProperty.getType();
  -            if (List.class.isAssignableFrom(type)) {
  +        // Set the value in an array
  +        if (indexedProperty.getClass().isArray()) {
  +            Array.set(indexedProperty, index, value);
  +        } else if (indexedProperty instanceof List) {
  +            ((List)indexedProperty).set(index, value);
  +        } else {
  +            throw new IllegalArgumentException
  +                ("Non-indexed property for '" + name + "[" + index + "]' "
  +                            + indexedProperty.getClass().getName());
  +        }
   
  -                try {
  -                    prop = type.newInstance();
  -                    set(name, prop);
  -                }
  -                catch (Exception ex) {
  -                    throw new IllegalArgumentException
  -                        ("Error instantiating List of type '" + type.getName() +
  -                                      "' for '" + name + "[" + index + "]'");
  -                }
  +    }
   
  -            } else if (type.isArray()) {
  +    /**
  +     * Set the value of a mapped property with the specified name.
  +     *
  +     * @param name Name of the property whose value is to be set
  +     * @param key Key of the property to be set
  +     * @param value Value to which this property is to be set
  +     *
  +     * @exception ConversionException if the specified value cannot be
  +     *  converted to the type required for this property
  +     * @exception IllegalArgumentException if there is no property
  +     *  of the specified name
  +     * @exception IllegalArgumentException if the specified property
  +     *  exists, but is not mapped
  +     */
  +    public void set(String name, String key, Object value) {
   
  -                prop = Array.newInstance(type.getComponentType(), index+1);
  -                set(name, prop);
  +        // If the 'mapped' property doesn't exist, then add it
  +        if (!isDynaProperty(name)) {
  +            set(name, defaultMappedProperty(name));
  +        }
   
  -            } else {
  +        // Get the mapped property
  +        Object mappedProperty = get(name);
   
  -                throw new IllegalArgumentException
  -                   ("Non-indexed property for '" + name + "[" + index + "]'");
  -            }
  +        // Check that the property is mapped
  +        if (!dynaClass.getDynaProperty(name).isMapped()) {
  +            throw new IllegalArgumentException
  +                ("Non-mapped property for '" + name + "(" + key + ")'"
  +                            + dynaClass.getDynaProperty(name).getType().getName());
           }
   
  -        // Grow the List or Array dynamically
  -        if (prop instanceof List) {
  +        // Set the value in the Map
  +        ((Map)mappedProperty).put(key, value);
   
  -            List list = (List)prop;
  +    }
  +
  +    // ------------------- protected Methods ----------------------------------
  +
  +    protected Object growIndexedProperty(String name, Object indexedProperty, int index) {
  +
  +        // Grow a List to the appropriate size
  +        if (indexedProperty instanceof List) {
  +
  +            List list = (List)indexedProperty;
               while (index >= list.size()) {
                   list.add(null);
               }
   
  -        } else if ((prop.getClass().isArray())) {
  +        }
  +
  +        // Grow an Array to the appropriate size
  +        if ((indexedProperty.getClass().isArray())) {
   
  -            int length = Array.getLength(prop);
  +            int length = Array.getLength(indexedProperty);
               if (index >= length) {
  -                Object newArray = Array.newInstance(prop.getClass().getComponentType(), (index + 1));
  -                System.arraycopy(prop, 0, newArray, 0, length);
  -                set(name, newArray);
  +                Class componentType = indexedProperty.getClass().getComponentType();
  +                Object newArray = Array.newInstance(componentType, (index + 1));
  +                System.arraycopy(indexedProperty, 0, newArray, 0, length);
  +                indexedProperty = newArray;
  +                set(name, indexedProperty);
  +                int newLength = Array.getLength(indexedProperty);
  +                for (int i = length; i < newLength; i++) {
  +                    Array.set(indexedProperty, i, createProperty(name+"["+i+"]", componentType));
  +                }
               }
           }
   
  -        super.set(name, index, value);
  +        return indexedProperty;
   
       }
   
       /**
  -     * <p>Creates a new <code>ArrayList</code> for an 'indexed' property
  -     *    which doesn't exist.</p>
  -     *
  -     * <p>This method shouls be overriden if an alternative <code>List</code>
  -     *    or <code>Array</code> implementation is required for 'indexed' properties.</p>
  -     *
  -     * @param name Name of the 'indexed property.
  +     * Create a new Instance of a Property
        */
  -    protected Object newIndexedProperty(String name) {
  +    protected Object createProperty(String name, Class type) {
   
  -        return new ArrayList();
  +        // Create Lists, arrays or DynaBeans
  +        if (type.isArray() || List.class.isAssignableFrom(type)) {
  +            return createIndexedProperty(name, type);
  +        }
  +
  +        if (Map.class.isAssignableFrom(type)) {
  +            return createMappedProperty(name, type);
  +        }
  +
  +        if (DynaBean.class.isAssignableFrom(type)) {
  +            return createDynaBeanProperty(name, type);
  +        }
  +
  +        if (type.isPrimitive()) {
  +            return createPrimitiveProperty(name, type);
  +        }
  +
  +        if (Number.class.isAssignableFrom(type)) {
  +            return createNumberProperty(name, type);
  +        }
  +
  +        return createOtherProperty(name, type);
   
       }
   
       /**
  -     * Set the value of a mapped property with the specified name.
  -     *
  -     * @param name Name of the property whose value is to be set
  -     * @param key Key of the property to be set
  -     * @param value Value to which this property is to be set
  -     *
  -     * @exception ConversionException if the specified value cannot be
  -     *  converted to the type required for this property
  -     * @exception IllegalArgumentException if there is no property
  -     *  of the specified name
  -     * @exception IllegalArgumentException if the specified property
  -     *  exists, but is not mapped
  +     * Create a new Instance of an 'Indexed' Property
        */
  -    public void set(String name, String key, Object value) {
  +    protected Object createIndexedProperty(String name, Class type) {
   
  -        // If the 'mapped' property doesn't exist, then add it
  -        if (!isDynaProperty(name)) {
  -            set(name, newMappedProperty(name));
  -        }
  +        // Create the indexed object
  +        Object indexedProperty = null;
  +
  +        if (type == null) {
   
  -        // Check if its an Indexed Property
  -        DynaProperty dynaProperty = mutableDynaClass.getDynaProperty(name);
  -        if (!dynaProperty.isMapped()) {
  -            throw new IllegalArgumentException("Non-mapped property for '" +
  -                 name + "(" + key + ")', type is '" + dynaProperty.getType().getName()+"'");
  +            indexedProperty = defaultIndexedProperty(name);
  +
  +        } else if (type.isArray()) {
  +
  +            indexedProperty = Array.newInstance(type.getComponentType(), 0);
  +
  +        } else if (List.class.isAssignableFrom(type)) {
  +            if (type.isInterface()) {
  +                indexedProperty = defaultIndexedProperty(name);
  +            } else {
  +                try {
  +                    indexedProperty = type.newInstance();
  +                }
  +                catch (Exception ex) {
  +                    throw new IllegalArgumentException
  +                        ("Error instantiating indexed property of type '" +
  +                                   type.getName() + "' for '" + name + "' " + ex);
  +                }
  +            }
  +        } else {
  +
  +            throw new IllegalArgumentException
  +                    ("Non-indexed property of type '" + type.getName() + "' for '" + name + "'");
           }
   
  -        // Instantiate the mapped property
  -        Object prop = get(name);
  -        if (prop == null) {
  -            Class type = dynaProperty.getType();
  +        return indexedProperty;
  +
  +    }
  +
  +    /**
  +     * Create a new Instance of a 'Mapped' Property
  +     */
  +    protected Object createMappedProperty(String name, Class type) {
  +
  +        // Create the mapped object
  +        Object mappedProperty = null;
  +
  +        if (type == null) {
  +
  +            mappedProperty = defaultMappedProperty(name);
  +
  +        } else if (type.isInterface()) {
  +
  +            mappedProperty = defaultMappedProperty(name);
  +
  +        } else if (Map.class.isAssignableFrom(type)) {
               try {
  -                set(name, type.newInstance());
  +                mappedProperty = type.newInstance();
               }
               catch (Exception ex) {
                   throw new IllegalArgumentException
  -                    ("Error instantiating Map of type '" + type.getName() +
  -                                      "' for '" + name + "(" + key + ")'");
  +                    ("Error instantiating mapped property of type '" + type.getName() + "' for '" + name + "' " + ex);
               }
  +        } else {
  +
  +            throw new IllegalArgumentException
  +                    ("Non-mapped property of type '" + type.getName() + "' for '" + name + "'");
           }
   
  +        return mappedProperty;
  +
  +    }
   
  -        // Set the 'mapped' property's value
  -        super.set(name, key, value);
  +    /**
  +     * Create a new Instance of a 'Mapped' Property
  +     */
  +    protected Object createDynaBeanProperty(String name, Class type) {
  +        try {
  +            return type.newInstance();
  +        }
  +        catch (Exception ex) {
  +            if (logger.isWarnEnabled()) {
  +                logger.warn("Error instantiating DynaBean property of type '" + type.getName() + "' for '" + name + "' " + ex);
  +            }
  +            return null;
  +        }
  +    }
  +
  +    /**
  +     * Create a new Instance of a 'Primitive' Property
  +     */
  +    protected Object createPrimitiveProperty(String name, Class type) {
  +
  +        if (type == Boolean.TYPE) {
  +            return Boolean.FALSE;
  +        } else if (type == Integer.TYPE) {
  +            return Integer_ZERO;
  +        } else if (type == Long.TYPE) {
  +            return Long_ZERO;
  +        } else if (type == Double.TYPE) {
  +            return Double_ZERO;
  +        } else if (type == Float.TYPE) {
  +            return Float_ZERO;
  +        } else if (type == Byte.TYPE) {
  +            return Byte_ZERO;
  +        } else if (type == Short.TYPE) {
  +            return Short_ZERO;
  +        } else if (type == Character.TYPE) {
  +            return Character_SPACE;
  +        } else {
  +            return null;
  +        }
  +
  +    }
  +
  +    /**
  +     * Create a new Instance of a 'Primitive' Property
  +     */
  +    protected Object createNumberProperty(String name, Class type) {
  +
  +        return null;
  +
  +    }
  +
  +    /**
  +     * Create a new Instance of a 'Mapped' Property
  +     */
  +    protected Object createOtherProperty(String name, Class type) {
  +
  +        if (type == String.class || type == Boolean.class ||
  +            type == Character.class || Date.class.isAssignableFrom(type)) {
  +            return null;
  +        }
   
  +        try {
  +            return type.newInstance();
  +        }
  +        catch (Exception ex) {
  +            if (logger.isWarnEnabled()) {
  +                logger.warn("Error instantiating property of type '" + type.getName() + "' for '" + name + "' " + ex);
  +            }
  +            return null;
  +        }
  +    }
   
  +    /**
  +     * <p>Creates a new <code>ArrayList</code> for an 'indexed' property
  +     *    which doesn't exist.</p>
  +     *
  +     * <p>This method shouls be overriden if an alternative <code>List</code>
  +     *    or <code>Array</code> implementation is required for 'indexed' properties.</p>
  +     *
  +     * @param name Name of the 'indexed property.
  +     */
  +    protected Object defaultIndexedProperty(String name) {
  +        return new ArrayList();
       }
   
       /**
  @@ -417,10 +778,8 @@
        *
        * @param name Name of the 'mapped property.
        */
  -    protected Map newMappedProperty(String name) {
  -
  +    protected Map defaultMappedProperty(String name) {
           return new HashMap();
  -
       }
   
       /**
  @@ -428,14 +787,49 @@
        */
       protected boolean isDynaProperty(String name) {
   
  +        if (name == null) {
  +            throw new IllegalArgumentException("No property name specified");
  +        }
  +
           // Handle LazyDynaClasses
  -        if (mutableDynaClass instanceof LazyDynaClass) {
  -            return ((LazyDynaClass)mutableDynaClass).isDynaProperty(name);
  +        if (dynaClass instanceof LazyDynaClass) {
  +            return ((LazyDynaClass)dynaClass).isDynaProperty(name);
           }
   
           // Handle other MutableDynaClass
  -        return mutableDynaClass.getDynaProperty(name) == null ? false : true;
  +        return dynaClass.getDynaProperty(name) == null ? false : true;
  +
  +    }
  +
  +    /**
  +     * Is an object of the source class assignable to the destination class?
  +     *
  +     * @param dest Destination class
  +     * @param source Source class
  +     */
  +    protected boolean isAssignable(Class dest, Class source) {
   
  +        if (dest.isAssignableFrom(source) ||
  +                ((dest == Boolean.TYPE) && (source == Boolean.class)) ||
  +                ((dest == Byte.TYPE) && (source == Byte.class)) ||
  +                ((dest == Character.TYPE) && (source == Character.class)) ||
  +                ((dest == Double.TYPE) && (source == Double.class)) ||
  +                ((dest == Float.TYPE) && (source == Float.class)) ||
  +                ((dest == Integer.TYPE) && (source == Integer.class)) ||
  +                ((dest == Long.TYPE) && (source == Long.class)) ||
  +                ((dest == Short.TYPE) && (source == Short.class))) {
  +            return (true);
  +        } else {
  +            return (false);
  +        }
  +
  +    }
  +
  +    /**
  +     * <p>Creates a new instance of the <code>Map</code></p>
  +     */
  +    protected Map newMap() {
  +        return new HashMap();
       }
   
   }
  
  
  
  1.1                  jakarta-commons/beanutils/src/java/org/apache/commons/beanutils/LazyDynaMap.java
  
  Index: LazyDynaMap.java
  ===================================================================
  /*
   * Copyright 2004 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.commons.beanutils;
  
  import java.util.Map;
  import java.util.Iterator;
  
  /**
   * <p>Provides a <i>light weight</i> <code>DynaBean</code> facade to a <code>Map</code> with <i>lazy</i> map/list processing.</p>
   *
   * <p>Its a <i>light weight</i> <code>DynaBean</code> implementation because there is no
   *    actual <code>DynaClass</code> associated with this <code>DynaBean</code> - in fact
   *    it implements the <code>DynaClass</code> interface itself providing <i>pseudo</i> DynaClass
   *    behaviour from the actual values stored in the <code>Map</code>.</p>
   *
   * <p>As well providing rhe standard <code>DynaBean</code> access to the <code>Map</code>'s properties
   *    this class also provides the usual <i>Lazy</i> behaviour:</p>
   *    <ul>
   *       <li>Properties don't need to be pre-defined in a <code>DynaClass</code></li>
   *       <li>Indexed properties (<code>Lists</code> or <code>Arrays</code>) are automatically instantiated
   *           and <i>grown</i> so that they are large enough to cater for the index being set.</li>
   *       <li>Mapped properties are automatically instantiated.</li>
   *    </ul>
   *
   * <p><b><u><i>Restricted</i> DynaClass</u></b></p>
   *    <p>This class implements the <code>MutableDynaClass</code> interface.
   *       <code>MutableDynaClass</code> have a facility to <i>restrict</i> the <code>DynaClass</code>
   *       so that its properties cannot be modified. If the <code>MutableDynaClass</code> is
   *       restricted then calling any of the <code>set()</code> methods for a property which
   *       doesn't exist will result in a <code>IllegalArgumentException</code> being thrown.</p>
   *
   * @author Niall Pemberton
   */
  public class LazyDynaMap extends LazyDynaBean implements MutableDynaClass  {
  
      /**
       * The name of this DynaClass (analogous to the
       * <code>getName()</code> method of <code>java.lang.Class</code>).
       */
      protected String name;
  
      /**
       * Controls whether changes to this DynaClass's properties are allowed.
       */
      protected boolean restricted;
  
      /**
       * <p>Controls whether the <code>getDynaProperty()</code> method returns
       * null if a property doesn't exist - or creates a new one.</p>
       *
       * <p>Default is <code>false</code>.
       */
      protected boolean returnNull = false;
  
  
      // ------------------- Constructors ----------------------------------
  
      /**
       * Default Constructor.
       */
      public LazyDynaMap() {
          this(null, null, null);
      }
  
      /**
       * Construct a new <code>LazyDynaMap</code> with the specified name.
       *
       * @param name Name of this DynaBean class
       */
      public LazyDynaMap(String name) {
          this(name, null, null);
      }
  
      /**
       * Construct a new <code>LazyDynaMap</code> with the specified <code>Map</code>.
       *
       * @param values The Map backing this <code>LazyDynaMap</code>
       */
      public LazyDynaMap(Map values) {
          this(null, values, null);
      }
  
      /**
       * Construct a new <code>LazyDynaMap</code> with the specified properties.
       *
       * @param name Name of this DynaBean class
       * @param properties Property descriptors for the supported properties
       */
      public LazyDynaMap(DynaProperty[] properties) {
          this(null, null, properties);
      }
  
      /**
       * Construct a new <code>LazyDynaMap</code> with the specified name and  <code>Map</code>.
       *
       * @param name Name of this DynaBean class
       * @param values The Map backing this <code>LazyDynaMap</code>
       */
      public LazyDynaMap(String name, Map values) {
          this(name, values, null);
      }
  
      /**
       * Construct a new <code>LazyDynaMap</code> with the specified name and properties.
       *
       * @param name Name of this DynaBean class
       * @param properties Property descriptors for the supported properties
       */
      public LazyDynaMap(String name, DynaProperty[] properties) {
          this(name, null, properties);
      }
  
      /**
       * Construct a new <code>LazyDynaMap</code> with the name, class and properties.
       *
       * @param name Name of this DynaBean class
       * @param valuesClass The implementation class for the <code>Map</code>
       * @param properties Property descriptors for the supported properties
       */
      public LazyDynaMap(Map values, DynaProperty properties[]) {
          this(null, values, properties);
      }
  
      /**
       * Construct a new <code>LazyDynaMap</code> with the name, class and properties.
       *
       * @param name Name of this DynaBean class
       * @param valuesClass The implementation class for the <code>Map</code>
       * @param properties Property descriptors for the supported properties
       */
      public LazyDynaMap(String name, Map values, DynaProperty properties[]) {
          initialize(name, values, properties);
      }
  
      /**
       * Construct a new <code>LazyDynaMap</code> with the specified name and properties.
       *
       * @param name Name of this DynaBean class
       * @param properties Property descriptors for the supported properties
       */
      public LazyDynaMap(DynaClass dynaClass) {
          this(dynaClass, null);
      }
  
      /**
       * Construct a new <code>LazyDynaMap</code> with the specified name and properties.
       *
       * @param name Name of this DynaBean class
       * @param properties Property descriptors for the supported properties
       */
      public LazyDynaMap(DynaClass dynaClass, Map values) {
          if (dynaClass == null) {
              initialize(null, values, null);
          } else {
              initialize(dynaClass.getName(), values, dynaClass.getDynaProperties());
          }
      }
  
      // ------------------- Public Methods ----------------------------------
  
      /**
       * Set the Map backing this <code>DynaBean</code>
       */
      public void setMap(Map values) {
          this.values = values;
      }
  
      // ------------------- DynaBean Methods ----------------------------------
  
      /**
       * Set the value of a simple property with the specified name.
       *
       * @param name Name of the property whose value is to be set
       * @param value Value to which this property is to be set
       */
      public void set(String name, Object value) {
  
          if (isRestricted() && !values.containsKey(name)) {
              throw new IllegalArgumentException
                      ("Invalid property name '" + name + "' (DynaClass is restricted)");
          }
  
          values.put(name, value);
  
      }
  
      // ------------------- DynaClass Methods ----------------------------------
  
      /**
       * Return the name of this DynaClass (analogous to the
       * <code>getName()</code> method of <code>java.lang.Class</code)
       */
      public String getName() {
          return this.name;
      }
  
      /**
       * <p>Return a property descriptor for the specified property.</p>
       *
       * <p>If the property is not found and the <code>returnNull</code> indicator is
       *    <code>true</code>, this method always returns <code>null</code>.</p>
       *
       * <p>If the property is not found and the <code>returnNull</code> indicator is
       *    <code>false</code> a new property descriptor is created and returned (although
       *    its not actually added to the DynaClass's properties). This is the default
       *    beahviour.</p>
       *
       * <p>The reason for not returning a <code>null</code> property descriptor is that
       *    <code>BeanUtils</code> uses this method to check if a property exists
       *    before trying to set it - since these <i>Map</i> implementations automatically
       *    add any new properties when they are set, returning <code>null</code> from
       *    this method would defeat their purpose.</p>
       *
       * @param name Name of the dynamic property for which a descriptor
       *  is requested
       *
       * @exception IllegalArgumentException if no property name is specified
       */
      public DynaProperty getDynaProperty(String name) {
  
          if (name == null)
              throw new IllegalArgumentException("Property name is missing.");
  
          // If it doesn't exist and returnNull is false
          // create a new DynaProperty
          if (!values.containsKey(name) && isReturnNull()) {
              return null;
          }
  
          Object value = values.get(name);
  
          if (value == null) {
              return new DynaProperty(name);
          } else {
              return new DynaProperty(name, value.getClass());
          }
  
      }
  
      /**
       * <p>Return an array of <code>ProperyDescriptors</code> for the properties
       * currently defined in this DynaClass.  If no properties are defined, a
       * zero-length array will be returned.</p>
       *
       * <p><strong>FIXME</strong> - Should we really be implementing
       * <code>getBeanInfo()</code> instead, which returns property descriptors
       * and a bunch of other stuff?</p>
       */
      public DynaProperty[] getDynaProperties() {
  
          int i = 0;
          DynaProperty[] properties = new DynaProperty[values.size()];
          Iterator iterator = values.keySet().iterator();
  
          while (iterator.hasNext()) {
              String name = (String)iterator.next();
              Object value = values.get(name);
              properties[i++] = new DynaProperty(name, value == null ? null : value.getClass());
          }
  
          return properties;
  
      }
  
      /**
       * Instantiate and return a new DynaBean instance, associated
       * with this DynaClass.
       *
       * @exception IllegalAccessException if the Class or the appropriate
       *  constructor is not accessible
       * @exception InstantiationException if this Class represents an abstract
       *  class, an array class, a primitive type, or void; or if instantiation
       *  fails for some other reason
       */
      public DynaBean newInstance()  {
          return new LazyDynaMap(this);
      }
  
  
      // ------------------- MutableDynaClass Methods ----------------------------------
  
      /**
       * Is this DynaClass currently restricted, if so, no changes to the
       * existing registration of property names, data types, readability, or
       * writeability are allowed.
       */
      public boolean isRestricted() {
          return restricted;
      }
  
      /**
       * Set whether this DynaClass is currently restricted. if so, no changes to the
       * existing registration of property names, data types, readability, or
       * writeability are allowed.
       */
      public void setRestricted(boolean restricted) {
          this.restricted = restricted;
      }
  
      /**
       * Add a new dynamic property with no restrictions on data type,
       * readability, or writeability.
       *
       * @param name Name of the new dynamic property
       *
       * @exception IllegalArgumentException if name is null
       */
      public void add(String name) {
          add(name, null);
      }
  
      /**
       * Add a new dynamic property with the specified data type, but with
       * no restrictions on readability or writeability.
       *
       * @param name Name of the new dynamic property
       * @param type Data type of the new dynamic property (null for no
       *  restrictions)
       *
       * @exception IllegalArgumentException if name is null
       * @exception IllegalStateException if this DynaClass is currently
       *  restricted, so no new properties can be added
       */
      public void add(String name, Class type) {
  
          if (name == null) {
              throw new IllegalArgumentException("Property name is missing.");
          }
  
          if (isRestricted())
              throw new IllegalStateException("DynaClass is currently restricted. No new properties can be added.");
  
          Object value = values.get(name);
  
          // Check if the property already exists
          if (value == null) {
              values.put(name, type == null ? null : createProperty(name, type));
          }
  
      }
  
      /**
       * <p>Add a new dynamic property with the specified data type, readability,
       * and writeability.</p>
       *
       * <p><strong>N.B.</strong>Support for readable/writeable properties has not been implemented
       *    and this method always throws a <code>UnsupportedOperationException</code>.</p>
       *
       * <p>I'm not sure the intention of the original authors for this method, but it seems to
       *    me that readable/writable should be attributes of the <code>DynaProperty</code> class
       *    (which they are not) and is the reason this method has not been implemented.</p>
       *
       * @param name Name of the new dynamic property
       * @param type Data type of the new dynamic property (null for no
       *  restrictions)
       * @param readable Set to <code>true</code> if this property value
       *  should be readable
       * @param writeable Set to <code>true</code> if this property value
       *  should be writeable
       *
       * @exception UnsupportedOperationException anytime this method is called
       */
      public void add(String name, Class type, boolean readable, boolean writeable) {
          throw new java.lang.UnsupportedOperationException("readable/writable properties not supported");
      }
  
      /**
       * Add a new dynamic property.
       *
       * @param name Name of the new dynamic property
       * @param type Property the new dynamic property
       *
       * @exception IllegalArgumentException if name is null
       */
      protected void add(DynaProperty property) {
          add(property.getName(), property.getType());
      }
  
      /**
       * Remove the specified dynamic property, and any associated data type,
       * readability, and writeability, from this dynamic class.
       * <strong>NOTE</strong> - This does <strong>NOT</strong> cause any
       * corresponding property values to be removed from DynaBean instances
       * associated with this DynaClass.
       *
       * @param name Name of the dynamic property to remove
       *
       * @exception IllegalArgumentException if name is null
       * @exception IllegalStateException if this DynaClass is currently
       *  restricted, so no properties can be removed
       */
      public void remove(String name) {
  
          if (name == null) {
              throw new IllegalArgumentException("Property name is missing.");
          }
  
          if (isRestricted()) {
              throw new IllegalStateException("DynaClass is currently restricted. No properties can be removed.");
          }
  
          // Remove, if property doesn't exist
          if (values.containsKey(name)) {
              values.remove(name);
          }
  
      }
  
  
      // ------------------- Additional Public Methods ----------------------------------
  
      /**
       * Should this DynaClass return a <code>null</code> from
       * the <code>getDynaProperty(name)</code> method if the property
       * doesn't exist.
       */
      public boolean isReturnNull() {
          return returnNull;
      }
  
      /**
       * Set whether this DynaClass should return a <code>null</code> from
       * the <code>getDynaProperty(name)</code> method if the property
       * doesn't exist.
       */
      public void setReturnNull(boolean returnNull) {
          this.returnNull = returnNull;
      }
  
  
      // ------------------- Protected Methods ----------------------------------
  
      /**
       * Initialize the  the new <code>LazyDynaMap</code> with the name, Map and properties.
       *
       * @param name Name of this DynaBean class
       * @param valuesClass The implementation class for the <code>Map</code>
       * @param properties Property descriptors for the supported properties
       */
      protected void initialize(String name, Map values, DynaProperty properties[]) {
  
          this.dynaClass = this;
          this.name      = name   == null ? "LazyDynaMap" : name;
          this.values    = values == null ? newMap()      : values;
  
          if (properties != null) {
              for (int i = 0; i < properties.length; i++) {
                  add(properties[i]);
              }
          }
      }
  
     /**
       * <p>Indicate whether a property actually exists.</p>
       *
       * <p><strong>N.B.</strong> Using <code>getDynaProperty(name) == null</code>
       * doesn't work in this implementation because that method might
       * return a DynaProperty if it doesn't exist (depending on the
       * <code>returnNull</code> indicator).</p>
       *
       * @exception IllegalArgumentException if no property name is specified
       */
      protected boolean isDynaProperty(String name) {
  
          if (name == null) {
              throw new IllegalArgumentException("Property name is missing.");
          }
  
          return values.containsKey(name);
  
      }
  
  }
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org