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: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]