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