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/05 02:48:12 UTC
cvs commit: jakarta-commons/beanutils/src/test/org/apache/commons/beanutils LazyDynaBeanTestCase.java LazyDynaClassTestCase.java
niallp 2004/07/04 17:48:12
Added: beanutils/src/java/org/apache/commons/beanutils
LazyDynaBean.java LazyDynaClass.java
beanutils/src/test/org/apache/commons/beanutils
LazyDynaBeanTestCase.java
LazyDynaClassTestCase.java
Log:
Add LazyDynaBean, LazyDynaClass and Test Cases
Revision Changes Path
1.1 jakarta-commons/beanutils/src/java/org/apache/commons/beanutils/LazyDynaBean.java
Index: LazyDynaBean.java
===================================================================
/*
* Copyright 2001-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.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.lang.reflect.Array;
/**
* <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>
*
* <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
* each of these types:</p>
* <ul>
* <li><i>Simple</i> property methods - <code>get(name)</code> and <code>set(name, value)</code></li>
* <li><i>Indexed</i> property methods - <code>get(name, index)</code> and <code>set(name, index, value)</code></li>
* <li><i>Mapped</i> property methods - <code>get(name, key)</code> and <code>set(name, key, value)</code></li>
* </ul>
*
* <p><b><u>Getting Property Values</u></b></p>
* <p>Calling any of the <code>get()</code> methods, for a property which
* doesn't exist, returns <code>null</code> in this implementation.</p>
*
* <p><b><u>Setting Simple Properties</u></b></p>
* <p>The <code>LazyDynaBean</code> will automatically add a property to the <code>DynaClass</code>
* if it doesn't exist when the <code>set(name, value)</code> method is called.</p>
*
* <code>DynaBean myBean = new LazyDynaBean();</code></br>
* <code>myBean.set("myProperty", "myValue");</code></br>
*
* <p><b><u>Setting Indexed Properties</u></b></p>
* <p>If the property <b>doesn't</b> exist, the <code>LazyDynaBean</code> will automatically add
* a property with an <code>ArrayList</code> type to the <code>DynaClass</code> when
* the <code>set(name, index, value)</code> method is called.
* It will also instantiate a new <code>ArrayList</code> and automatically <i>grow</i>
* the <code>List</code> so that it is big enough to accomodate the index being set.
* <code>ArrayList</code> is the default indexed property that LazyDynaBean uses but
* this can be easily changed by overriding the <code>newIndexedProperty(name)</code>
* method.</p>
*
* <code>DynaBean myBean = new LazyDynaBean();</code></br>
* <code>myBean.set("myIndexedProperty", 0, "myValue1");</code></br>
* <code>myBean.set("myIndexedProperty", 1, "myValue2");</code></br>
*
* <p>If the indexed property <b>does</b> exist in the <code>DynaClass</code> but is set to
* <code>null</code> in the <code>LazyDynaBean</code>, then it will instantiate a
* new <code>List</code> or <code>Array</code> as specified by the property's type
* in the <code>DynaClass</code> and automatically <i>grow</i> the <code>List</code>
* or <code>Array</code> so that it is big enough to accomodate the index being set.</p>
*
* <code>DynaBean myBean = new LazyDynaBean();</code></br>
* <code>MutableDynaClass myClass = (MutableDynaClass)myBean.getDynaClass();</code></br>
* <code>myClass.add("myIndexedProperty", int[].class);</code></br>
* <code>myBean.set("myIndexedProperty", 0, new Integer(10));</code></br>
* <code>myBean.set("myIndexedProperty", 1, new Integer(20));</code></br>
*
* <p><b><u>Setting Mapped Properties</u></b></p>
* <p>If the property <b>doesn't</b> exist, the <code>LazyDynaBean</code> will automatically add
* a property with a <code>HashMap</code> type to the <code>DynaClass</code> and
* instantiate a new <code>HashMap</code> in the DynaBean when the
* <code>set(name, key, value)</code> method is called. <code>HashMap</code> is the default
* mapped property that LazyDynaBean uses but this can be easily changed by overriding
* the <code>newMappedProperty(name)</code> method.</p>
*
* <code>DynaBean myBean = new LazyDynaBean();</code></br>
* <code>myBean.set("myMappedProperty", "myKey", "myValue");</code></br>
*
* <p>If the mapped property <b>does</b> exist in the <code>DynaClass</code> but is set to
* <code>null</code> in the <code>LazyDynaBean</code>, then it will instantiate a
* new <code>Map</code> as specified by the property's type in the <code>DynaClass</code>.</p>
*
* <code>DynaBean myBean = new LazyDynaBean();</code></br>
* <code>MutableDynaClass myClass = (MutableDynaClass)myBean.getDynaClass();</code></br>
* <code>myClass.add("myMappedProperty", TreeMap.class);</code></br>
* <code>myBean.set("myMappedProperty", "myKey", "myValue");</code></br>
*
* <p><b><u><i>Restricted</i> DynaClass</u></b></p>
* <p><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>
*
* @see LazyDynaClass
* @author Niall Pemberton
*/
public class LazyDynaBean extends BasicDynaBean {
/**
* The <code>MutableDynaClass</code> "base class" that this DynaBean
* is associated with.
*/
protected MutableDynaClass mutableDynaClass;
/**
* Construct a new <code>LazyDynaBean</code> with a <code>LazyDynaClass</code> instance.
*/
public LazyDynaBean() {
this(new LazyDynaClass());
}
/**
* Construct a new <code>LazyDynaBean</code> with a <code>LazyDynaClass</code> instance.
*
* @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>.
*
* @param dynaClass The DynaClass we are associated with
*/
public LazyDynaBean(DynaClass dynaClass) {
super(dynaClass);
if (!(dynaClass instanceof MutableDynaClass))
throw new IllegalArgumentException("DynaClass must be a MutableDynaClass type: " +
dynaClass.getClass().getName());
mutableDynaClass = (MutableDynaClass)dynaClass;
}
/**
* <p>Return the value of a simple property with the specified name.</p>
*
* <p><strong>N.B.</strong> Returns <code>null</code> if there is no property
* of the specified name.</p>
*
* @param name Name of the property whose value is to be retrieved.
*/
public Object get(String name) {
if (isDynaProperty(name)) {
return super.get(name);
} else {
return null;
}
}
/**
* <p>Return the value of an indexed property with the specified name.</p>
*
* <p><strong>N.B.</strong> Returns <code>null</code> if there is no 'indexed'
* property of the specified name.</p>
*
* @param name Name of the property whose value is to be retrieved
* @param index Index of the value to be retrieved
*
* @exception IllegalArgumentException if the specified property
* exists, but is not indexed
* @exception IndexOutOfBoundsException if the specified index
* is outside the range of the underlying property
*/
public Object get(String name, int index) {
if (get(name) == null) {
return null;
} else {
return super.get(name, index);
}
}
/**
* <p>Return the value of a mapped property with the specified name.</p>
*
* <p><strong>N.B.</strong> Returns <code>null</code> if there is no 'mapped'
* property of the specified name.</p>
*
* @param name Name of the property whose value is to be retrieved
* @param key Key of the value to be retrieved
*
* @exception IllegalArgumentException if the specified property
* exists, but is not mapped
*/
public Object get(String name, String key) {
if (get(name) == null) {
return null;
} else {
return super.get(name, key);
}
}
/**
* 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
*
* @exception IllegalArgumentException if this is not an existing property
* name for our DynaClass and the MutableDynaClass is restricted
* @exception ConversionException if the specified value cannot be
* converted to the type required for this property
* @exception NullPointerException if an attempt is made to set a
* primitive property to null
*/
public void set(String name, Object value) {
// If the property doesn't exist, then add it
if (!isDynaProperty(name)) {
if (mutableDynaClass.isRestricted()) {
throw new IllegalArgumentException
("Invalid property name '" + name + "' (DynaClass is restricted)");
}
if (value == null) {
mutableDynaClass.add(name);
} else {
mutableDynaClass.add(name, value.getClass());
}
}
// Set the property's value
super.set(name, value);
}
/**
* Set the value of an indexed property with the specified name.
*
* @param name Name of the property whose value is to be set
* @param index Index 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 indexed
* @exception IndexOutOfBoundsException if the specified index
* is outside the range of the underlying property
*/
public void set(String name, int index, Object value) {
// If the 'indexed' property doesn't exist, then add it
if (!isDynaProperty(name)) {
set(name, newIndexedProperty(name));
}
// Check if its an Indexed Property
DynaProperty dynaProperty = mutableDynaClass.getDynaProperty(name);
if (!dynaProperty.isIndexed()) {
throw new IllegalArgumentException
("Non-indexed property for '" + name + "[" + index + "]', type is '" +
dynaProperty.getType().getName()+"'");
}
// Instantiate the indexed property
Object prop = get(name);
if (prop == null) {
Class type = dynaProperty.getType();
if (List.class.isAssignableFrom(type)) {
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()) {
prop = Array.newInstance(type.getComponentType(), index+1);
set(name, prop);
} else {
throw new IllegalArgumentException
("Non-indexed property for '" + name + "[" + index + "]'");
}
}
// Grow the List or Array dynamically
if (prop instanceof List) {
List list = (List)prop;
while (index >= list.size()) {
list.add(null);
}
} else if ((prop.getClass().isArray())) {
int length = Array.getLength(prop);
if (index >= length) {
Object newArray = Array.newInstance(prop.getClass().getComponentType(), (index + 1));
System.arraycopy(prop, 0, newArray, 0, length);
set(name, newArray);
}
}
super.set(name, index, value);
}
/**
* <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 newIndexedProperty(String name) {
return new ArrayList();
}
/**
* 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) {
// If the 'mapped' property doesn't exist, then add it
if (!isDynaProperty(name)) {
set(name, newMappedProperty(name));
}
// 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()+"'");
}
// Instantiate the mapped property
Object prop = get(name);
if (prop == null) {
Class type = dynaProperty.getType();
try {
set(name, type.newInstance());
}
catch (Exception ex) {
throw new IllegalArgumentException
("Error instantiating Map of type '" + type.getName() +
"' for '" + name + "(" + key + ")'");
}
}
// Set the 'mapped' property's value
super.set(name, key, value);
}
/**
* <p>Creates a new <code>HashMap</code> for a 'mapped' property
* which doesn't exist.</p>
*
* <p>This method can be overriden if an alternative <code>Map</code>
* implementation is required for 'mapped' properties.</p>
*
* @param name Name of the 'mapped property.
*/
protected Map newMappedProperty(String name) {
return new HashMap();
}
/**
* Indicates if there is a property with the specified name.
*/
protected boolean isDynaProperty(String name) {
// Handle LazyDynaClasses
if (mutableDynaClass instanceof LazyDynaClass) {
return ((LazyDynaClass)mutableDynaClass).isDynaProperty(name);
}
// Handle other MutableDynaClass
return mutableDynaClass.getDynaProperty(name) == null ? false : true;
}
}
1.1 jakarta-commons/beanutils/src/java/org/apache/commons/beanutils/LazyDynaClass.java
Index: LazyDynaClass.java
===================================================================
/*
* Copyright 2001-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;
/**
* <p>DynaClass which implements the <code>MutableDynaClass</code> interface.</p>
*
* <p>A <code>MutableDynaClass</code> is a specialized extension to <code>DynaClass</code>
* that allows properties to be added or removed dynamically.</p>
*
* <p>This implementation has one slightly unusual default behaviour - calling
* the <code>getDynaProperty(name)</code> method for a property which doesn't
* exist returns a <code>DynaProperty</code> rather than <code>null</code>. The
* reason for this is that <code>BeanUtils</code> calls this method to check if
* a property exists before trying to set the value. This would defeat the object
* of the <code>LazyDynaBean</code> which automatically adds missing properties
* when any of its <code>set()</code> methods are called. For this reason the
* <code>isDynaProperty(name)</code> method has been added to this implementation
* in order to determine if a property actually exists. If the more <i>normal</i>
* behaviour of returning <code>null</code> is required, then this can be achieved
* by calling the <code>setReturnNull(true)</code>.</p>
*
* <p>The <code>add(name, type, readable, writable)</code> method is not implemented
* and always throws an <code>UnsupportedOperationException</code>. I believe
* this attributes need to be added to the <code>DynaProperty</code> class
* in order to control read/write facilities.</p>
*
* @see LazyDynaBean
* @see MutableDynaClass
* @author Niall Pemberton
*/
public class LazyDynaClass extends BasicDynaClass implements MutableDynaClass {
/**
* 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;
/**
* Construct a new LazyDynaClass with default parameters.
*/
public LazyDynaClass() {
super(null, LazyDynaBean.class);
}
/**
* Construct a new LazyDynaClass with the specified parameters.
*
* @param name Name of this DynaBean class
* @param dynaBeanClass The implementation class for new instances
*/
public LazyDynaClass(String name) {
super(name, LazyDynaBean.class);
}
/**
* Construct a new LazyDynaClass with the specified parameters.
*
* @param name Name of this DynaBean class
* @param dynaBeanClass The implementation class for new instances
*/
public LazyDynaClass(String name, Class dynaBeanClass) {
super(name, dynaBeanClass);
}
/**
* 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);
}
/**
* 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;
}
/**
* 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;
}
/**
* 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
* @exception IllegalStateException if this DynaClass is currently
* restricted, so no new properties can be added
*/
public void add(String name) {
add(new DynaProperty(name));
}
/**
* 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) {
add(new DynaProperty(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
* @exception IllegalStateException if this DynaClass is currently
* restricted, so no new properties can be added
*/
protected void add(DynaProperty property) {
if (property.getName() == null)
throw new IllegalArgumentException("Property name is missing.");
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)
return;
// Create a new property array with the specified property
DynaProperty[] oldProperties = getDynaProperties();
DynaProperty[] newProperties = new DynaProperty[oldProperties.length+1];
System.arraycopy(oldProperties, 0, newProperties, 0, oldProperties.length);
newProperties[oldProperties.length] = property;
// Update the properties
setProperties(newProperties);
}
/**
* 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.");
// Ignore if property doesn't exist
if (propertiesMap.get(name) == null)
return;
// Create a new property array of without the specified property
DynaProperty[] oldProperties = getDynaProperties();
DynaProperty[] newProperties = new DynaProperty[oldProperties.length-1];
int j = 0;
for (int i = 0; i < oldProperties.length; i++) {
if (!(name.equals(oldProperties[i].getName()))) {
newProperties[j] = oldProperties[i];
j++;
}
}
// Update the properties
setProperties(newProperties);
}
/**
* <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>Lazy</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.");
DynaProperty dynaProperty = (DynaProperty)propertiesMap.get(name);
// If it doesn't exist and returnNull is false
// create a new DynaProperty
if (dynaProperty == null && !isReturnNull() && !isRestricted()) {
dynaProperty = new DynaProperty(name);
}
return dynaProperty;
}
/**
* <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
*/
public boolean isDynaProperty(String name) {
if (name == null)
throw new IllegalArgumentException("Property name is missing.");
return propertiesMap.get(name) == null ? false : true;
}
}
1.1 jakarta-commons/beanutils/src/test/org/apache/commons/beanutils/LazyDynaBeanTestCase.java
Index: LazyDynaBeanTestCase.java
===================================================================
/*
* Copyright 2001-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.HashMap;
import java.util.TreeMap;
import java.util.ArrayList;
import java.util.LinkedList;
import java.lang.reflect.InvocationTargetException;
import junit.framework.TestCase;
import junit.framework.Test;
import junit.framework.TestSuite;
/**
* <p>Test Case for the <code>LazyDynaBean</code> implementation class.</p>
*
* @author Niall Pemberton
*/
public class LazyDynaBeanTestCase extends TestCase {
protected LazyDynaBean bean = null;
protected LazyDynaClass dynaClass = null;
protected String testProperty = "myProperty";
protected String testString1 = "myStringValue-1";
protected String testString2 = "myStringValue-2";
protected Integer testInteger1 = new Integer(30);
protected Integer testInteger2 = new Integer(40);
protected String testKey = "myKey";
// ---------------------------------------------------------- Constructors
/**
* Construct a new instance of this test case.
*
* @param name Name of the test case
*/
public LazyDynaBeanTestCase(String name) {
super(name);
}
// -------------------------------------------------- Overall Test Methods
/**
* Run thus Test
*/
public static void main(String[] args) {
junit.textui.TestRunner.run(suite());
}
/**
* Return the tests included in this test suite.
*/
public static Test suite() {
return (new TestSuite(LazyDynaBeanTestCase.class));
}
/**
* Set up instance variables required by this test case.
*/
public void setUp() throws Exception {
bean = new LazyDynaBean();
dynaClass = (LazyDynaClass)bean.getDynaClass();
dynaClass.setReturnNull(true);
}
/**
* Tear down instance variables required by this test case.
*/
public void tearDown() {
bean = null;
}
// ------------------------------------------------ Individual Test Methods
/**
* Test Getting/Setting a Simple Property
*/
public void testSimpleProperty() {
// Check the property & value doesn't exist
assertNull("Check Property doesn't exist", dynaClass.getDynaProperty(testProperty));
assertNull("Check Value is null", bean.get(testProperty));
// Set a new property - should add new property and set value
bean.set(testProperty, testInteger1);
assertEquals("Check First Value is correct", testInteger1, bean.get(testProperty));
assertEquals("Check Property type is correct", Integer.class, dynaClass.getDynaProperty(testProperty).getType());
// Set the property again - should set the new value
bean.set(testProperty, testInteger2);
assertEquals("Check Second Value is correct", testInteger2, bean.get(testProperty));
// Set the property again - with a different type, should fail
try {
bean.set(testProperty, testString1);
fail("expected ConversionException trying to set an Integer property to a String");
} catch (ConversionException expected) {
// expected result
}
}
/**
* Test Setting a Simple Property when MutableDynaClass is set to restricted
*/
public void testSimplePropertyRestricted() {
// Set the MutableDyanClass to 'restricted' (i.e. no new properties cab be added
dynaClass.setRestricted(true);
assertTrue("Check MutableDynaClass is restricted", dynaClass.isRestricted());
// Check the property & value doesn't exist
assertNull("Check Property doesn't exist", dynaClass.getDynaProperty(testProperty));
assertNull("Check Value is null", bean.get(testProperty));
// Set the property - should fail because property doesn't exist and MutableDynaClass is restricted
try {
bean.set(testProperty, testString1);
fail("expected IllegalArgumentException trying to add new property to restricted DynaClass");
} catch (IllegalArgumentException expected) {
// expected result
}
}
/**
* Test Getting/Setting a 'Mapped' Property - default HashMap property
*/
public void testMappedPropertyDefault() {
// Check the property & value doesn't exist
assertNull("Check Mapped Property doesn't exist", dynaClass.getDynaProperty(testProperty));
assertNull("Check Map is null", bean.get(testProperty));
assertNull("Check Mapped Value is null", bean.get(testProperty, testKey));
// Set a new mapped property - should add new HashMap property and set the mapped value
bean.set(testProperty, testKey, testInteger1);
assertEquals("Check Mapped Property exists", HashMap.class, bean.get(testProperty).getClass());
assertEquals("Check First Mapped Value is correct(a)", testInteger1, bean.get(testProperty, testKey));
assertEquals("Check First Mapped Value is correct(b)", testInteger1, ((HashMap)bean.get(testProperty)).get(testKey));
// Set the property again - should set the new value
bean.set(testProperty, testKey, testInteger2);
assertEquals("Check Second Mapped Value is correct(a)", testInteger2, bean.get(testProperty, testKey));
assertEquals("Check Second Mapped Value is correct(b)", testInteger2, ((HashMap)bean.get(testProperty)).get(testKey));
}
/**
* Test Getting/Setting a 'Mapped' Property - use TreeMap property
*/
public void testMappedPropertyTreeMap() {
// Check the property & value doesn't exist
assertNull("Check Mapped Property doesn't exist", dynaClass.getDynaProperty(testProperty));
assertNull("Check Map is null", bean.get(testProperty));
assertNull("Check Mapped Value is null", bean.get(testProperty, testKey));
// Add a 'TreeMap' property to the DynaClass
dynaClass.add(testProperty, TreeMap.class);
assertTrue("Check Property is mapped", dynaClass.getDynaProperty(testProperty).isMapped());
assertEquals("Check Property is correct type", TreeMap.class, dynaClass.getDynaProperty(testProperty).getType());
assertNull("Check mapped property is null", bean.get(testProperty));
// Set a new mapped property - should instatiate a new TreeMap property and set the mapped value
bean.set(testProperty, testKey, testInteger1);
assertEquals("Check Mapped Property exists", TreeMap.class, bean.get(testProperty).getClass());
assertEquals("Check First Mapped Value is correct(a)", testInteger1, bean.get(testProperty, testKey));
assertEquals("Check First Mapped Value is correct(b)", testInteger1, ((TreeMap)bean.get(testProperty)).get(testKey));
// Set the property again - should set the new value
bean.set(testProperty, testKey, testInteger2);
assertEquals("Check Second Mapped Value is correct(a)", testInteger2, bean.get(testProperty, testKey));
assertEquals("Check Second Mapped Value is correct(b)", testInteger2, ((TreeMap)bean.get(testProperty)).get(testKey));
}
/**
* Test Setting a 'Mapped' Property using PropertyUtils
*/
public void testMappedPropertyUtils() {
dynaClass.setReturnNull(false);
// Check the property & value doesn't exist
assertFalse("Check Mapped Property doesn't exist", dynaClass.isDynaProperty(testProperty));
assertNull("Check Map is null", bean.get(testProperty));
assertNull("Check Mapped Value is null", bean.get(testProperty, testKey));
// Set the mapped property using PropertyUtils
try {
PropertyUtils.setProperty(bean, testProperty+"("+testKey+")", testString1);
}
catch (NoSuchMethodException ex) {
fail("testIndexedPropertyUtils threw "+ex);
}
catch (InvocationTargetException ex) {
fail("testIndexedPropertyUtils threw "+ex);
}
catch (IllegalAccessException ex) {
fail("testIndexedPropertyUtils threw "+ex);
}
// Check property value correctly set
assertEquals("Check Mapped Bean Value is correct", testString1, bean.get(testProperty, testKey));
}
/**
* Test Setting a Mapped Property when MutableDynaClass is set to restricted
*/
public void testMappedPropertyRestricted() {
// Set the MutableDyanClass to 'restricted' (i.e. no new properties cab be added
dynaClass.setRestricted(true);
assertTrue("Check MutableDynaClass is restricted", dynaClass.isRestricted());
// Check the property & value doesn't exist
assertNull("Check Property doesn't exist", dynaClass.getDynaProperty(testProperty));
assertNull("Check Value is null", bean.get(testProperty));
// Set the property - should fail because property doesn't exist and MutableDynaClass is restricted
try {
bean.set(testProperty, testKey, testInteger1);
fail("expected IllegalArgumentException trying to add new property to restricted MutableDynaClass");
} catch (IllegalArgumentException expected) {
// expected result
}
}
/**
* Test setting mapped property for type which is not Map
*/
public void testMappedInvalidType() {
dynaClass.add(testProperty, String.class);
assertFalse("Check Property is not mapped", dynaClass.getDynaProperty(testProperty).isMapped());
try {
bean.set(testProperty, testKey, testInteger1);
fail("set(property, key, value) should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
// expected result
}
}
/**
* Test Getting/Setting an 'Indexed' Property - default ArrayList property
*/
public void testIndexedPropertyDefault() {
int index = 3;
// Check the property & value doesn't exist
assertNull("Check Indexed Property doesn't exist", dynaClass.getDynaProperty(testProperty));
assertNull("Check Indexed Property is null", bean.get(testProperty));
assertNull("Check Indexed value is null", bean.get(testProperty, index));
// Set the property, should create new ArrayList and set appropriate indexed value
bean.set(testProperty, index, testInteger1);
assertNotNull("Check Indexed Property is not null", bean.get(testProperty));
assertEquals("Check Indexed Property is correct type", ArrayList.class, bean.get(testProperty).getClass());
assertEquals("Check First Indexed Value is correct", testInteger1, bean.get(testProperty, index));
assertEquals("Check First Array length is correct", new Integer(index+1), new Integer(((ArrayList)bean.get(testProperty)).size()));
// Set a second indexed value, should automatically grow the ArrayList and set appropriate indexed value
index = index + 2;
bean.set(testProperty, index, testString1);
assertEquals("Check Second Indexed Value is correct", testString1, bean.get(testProperty, index));
assertEquals("Check Second Array length is correct", new Integer(index+1), new Integer(((ArrayList)bean.get(testProperty)).size()));
}
/**
* Test Getting/Setting a List 'Indexed' Property - use alternative List (LinkedList)
*/
public void testIndexedLinkedList() {
int index = 3;
// Check the property & value doesn't exist
assertNull("Check Indexed Property doesn't exist", dynaClass.getDynaProperty(testProperty));
assertNull("Check Indexed Property is null", bean.get(testProperty));
assertNull("Check Indexed value is null", bean.get(testProperty, index));
// Add a 'LinkedList' property to the DynaClass
dynaClass.add(testProperty, LinkedList.class);
assertTrue("Check Property is indexed", dynaClass.getDynaProperty(testProperty).isIndexed());
assertEquals("Check Property is correct type", LinkedList.class, dynaClass.getDynaProperty(testProperty).getType());
assertNull("Check Indexed property is null", bean.get(testProperty));
// Set the property, should instantiate a new LinkedList and set appropriate indexed value
bean.set(testProperty, index, testString1);
assertEquals("Check Property type is correct", LinkedList.class, bean.get(testProperty).getClass());
assertEquals("Check First Indexed Value is correct", testString1, bean.get(testProperty, index));
assertEquals("Check First Array length is correct", new Integer(index+1), new Integer(((LinkedList)bean.get(testProperty)).size()));
// Set a second indexed value, should automatically grow the LinkedList and set appropriate indexed value
index = index + 2;
bean.set(testProperty, index, testInteger1);
assertEquals("Check Second Indexed Value is correct", testInteger1, bean.get(testProperty, index));
assertEquals("Check Second Array length is correct", new Integer(index+1), new Integer(((LinkedList)bean.get(testProperty)).size()));
}
/**
* Test Getting/Setting a primitive array 'Indexed' Property - use int[]
*/
public void testIndexedPrimitiveArray() {
int index = 3;
int[] primitiveArray = new int[0];
// Check the property & value doesn't exist
assertNull("Check Indexed Property doesn't exist", dynaClass.getDynaProperty(testProperty));
assertNull("Check Indexed Property is null", bean.get(testProperty));
assertNull("Check Indexed value is null", bean.get(testProperty, index));
// Add a DynaProperty of type int[]
dynaClass.add(testProperty, primitiveArray.getClass());
assertEquals("Check Indexed Property exists", primitiveArray.getClass(), dynaClass.getDynaProperty(testProperty).getType());
assertNull("Check Indexed Property is null", bean.get(testProperty));
// Set an indexed value
bean.set(testProperty, index, testInteger1);
assertNotNull("Check Indexed Property is not null", bean.get(testProperty));
assertEquals("Check Indexed Property is correct type", primitiveArray.getClass(), bean.get(testProperty).getClass());
assertEquals("Check First Indexed Value is correct(a)", testInteger1, bean.get(testProperty, index));
assertEquals("Check First Indexed Value is correct(b)", testInteger1, new Integer(((int[])bean.get(testProperty))[index]));
assertEquals("Check Array length is correct", new Integer(index+1), new Integer(((int[])bean.get(testProperty)).length));
// Set a second indexed value, should automatically grow the int[] and set appropriate indexed value
index = index + 2;
bean.set(testProperty, index, testInteger2);
assertEquals("Check Second Indexed Value is correct(a)", testInteger2, bean.get(testProperty, index));
assertEquals("Check Second Indexed Value is correct(b)", testInteger2, new Integer(((int[])bean.get(testProperty))[index]));
assertEquals("Check Second Array length is correct", new Integer(index+1), new Integer(((int[])bean.get(testProperty)).length));
}
/**
* Test Getting/Setting an Object array 'Indexed' Property - use String[]
*/
public void testIndexedObjectArray() {
int index = 3;
Object objectArray = new String[0];
// Check the property & value doesn't exist
assertNull("Check Indexed Property doesn't exist", dynaClass.getDynaProperty(testProperty));
assertNull("Check Indexed Property is null", bean.get(testProperty));
assertNull("Check Indexed value is null", bean.get(testProperty, index));
// Add a DynaProperty of type String[]
dynaClass.add(testProperty, objectArray.getClass());
assertEquals("Check Indexed Property exists", objectArray.getClass(), dynaClass.getDynaProperty(testProperty).getType());
assertNull("Check Indexed Property is null", bean.get(testProperty));
// Set an indexed value
bean.set(testProperty, index, testString1);
assertNotNull("Check Indexed Property is not null", bean.get(testProperty));
assertEquals("Check Indexed Property is correct type", objectArray.getClass(), bean.get(testProperty).getClass());
assertEquals("Check First Indexed Value is correct(a)", testString1, bean.get(testProperty, index));
assertEquals("Check First Indexed Value is correct(b)", testString1, ((String[])bean.get(testProperty))[index]);
assertEquals("Check Array length is correct", new Integer(index+1), new Integer(((String[])bean.get(testProperty)).length));
// Set a second indexed value, should automatically grow the String[] and set appropriate indexed value
index = index + 2;
bean.set(testProperty, index, testString2);
assertEquals("Check Second Indexed Value is correct(a)", testString2, bean.get(testProperty, index));
assertEquals("Check Second Indexed Value is correct(b)", testString2, ((String[])bean.get(testProperty))[index]);
assertEquals("Check Second Array length is correct", new Integer(index+1), new Integer(((String[])bean.get(testProperty)).length));
}
/**
* Test Setting an 'Indexed' Property using PropertyUtils
*/
public void testIndexedPropertyUtils() {
int index = 3;
dynaClass.setReturnNull(false);
// Check the property & value doesn't exist
assertFalse("Check Indexed Property doesn't exist", dynaClass.isDynaProperty(testProperty));
assertNull("Check Indexed Property is null", bean.get(testProperty));
assertNull("Check Indexed value is null", bean.get(testProperty, index));
// Use PropertyUtils to set the indexed value
try {
PropertyUtils.setProperty(bean, testProperty+"["+index+"]", testString1);
}
catch (NoSuchMethodException ex) {
fail("testIndexedPropertyUtils threw "+ex);
}
catch (InvocationTargetException ex) {
fail("testIndexedPropertyUtils threw "+ex);
}
catch (IllegalAccessException ex) {
fail("testIndexedPropertyUtils threw "+ex);
}
// Check property value correctly set
assertEquals("Check Indexed Bean Value is correct", testString1, bean.get(testProperty, index));
}
/**
* Test Setting an Indexed Property when MutableDynaClass is set to restricted
*/
public void testIndexedPropertyRestricted() {
int index = 3;
// Set the MutableDyanClass to 'restricted' (i.e. no new properties cab be added
dynaClass.setRestricted(true);
assertTrue("Check MutableDynaClass is restricted", dynaClass.isRestricted());
// Check the property & value doesn't exist
assertNull("Check Property doesn't exist", dynaClass.getDynaProperty(testProperty));
assertNull("Check Value is null", bean.get(testProperty));
// Set the property - should fail because property doesn't exist and MutableDynaClass is restricted
try {
bean.set(testProperty, index, testInteger1);
fail("expected IllegalArgumentException trying to add new property to restricted MutableDynaClass");
} catch (IllegalArgumentException expected) {
// expected result
}
}
/**
* Test setting indexed property for type which is not List or Array
*/
public void testIndexedInvalidType() {
int index = 3;
dynaClass.add(testProperty, String.class);
assertFalse("Check Property is not indexed", dynaClass.getDynaProperty(testProperty).isIndexed());
try {
bean.set(testProperty, index, testString1);
fail("set(property, index, value) should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
// expected result
}
}
}
1.1 jakarta-commons/beanutils/src/test/org/apache/commons/beanutils/LazyDynaClassTestCase.java
Index: LazyDynaClassTestCase.java
===================================================================
/*
* Copyright 2001-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 junit.framework.TestCase;
import junit.framework.Test;
import junit.framework.TestSuite;
/**
* <p>Test Case for the <code>LazyDynaClass</code> implementation class.</p>
*
* @author Niall Pemberton
*/
public class LazyDynaClassTestCase extends TestCase {
protected LazyDynaClass dynaClass = null;
protected String testProperty = "myProperty";
// ---------------------------------------------------------- Constructors
/**
* Construct a new instance of this test case.
*
* @param name Name of the test case
*/
public LazyDynaClassTestCase(String name) {
super(name);
}
// -------------------------------------------------- Overall Test Methods
/**
* Run this Test
*/
public static void main(String[] args) {
junit.textui.TestRunner.run(suite());
}
/**
* Set up instance variables required by this test case.
*/
public void setUp() throws Exception {
dynaClass = new LazyDynaClass();
}
/**
* Return the tests included in this test suite.
*/
public static Test suite() {
return (new TestSuite(LazyDynaClassTestCase.class));
}
/**
* Tear down instance variables required by this test case.
*/
public void tearDown() {
dynaClass = null;
}
// ------------------------------------------------ Individual Test Methods
/**
* Test add(name) method
*/
public void testAddProperty1() {
dynaClass.add(testProperty);
DynaProperty dynaProperty = dynaClass.getDynaProperty(testProperty);
assertEquals("name is correct", testProperty, dynaProperty.getName());
assertEquals("type is correct", Object.class, dynaProperty.getType());
}
/**
* Test add(name, type) method
*/
public void testAddProperty2() {
dynaClass.add(testProperty, String.class);
DynaProperty dynaProperty = dynaClass.getDynaProperty(testProperty);
assertEquals("name is correct", testProperty, dynaProperty.getName());
assertEquals("type is correct", String.class, dynaProperty.getType());
}
/**
* Test add(name, type, readable, writable) method
*/
public void testAddProperty3() {
try {
dynaClass.add(testProperty, String.class, true, true);
fail("add(name, type, readable, writable) did not throw UnsupportedOperationException");
} catch (UnsupportedOperationException expected) {
// expected result
}
}
/**
* Test add(name) method with 'null' name
*/
public void testAddPropertyNullName1() {
try {
dynaClass.add((String)null);
fail("null property name not prevented");
} catch (IllegalArgumentException expected) {
// expected result
}
}
/**
* Test add(name, type) method with 'null' name
*/
public void testAddPropertyNullName2() {
try {
dynaClass.add(null, String.class);
fail("null property name not prevented");
} catch (IllegalArgumentException expected) {
// expected result
}
}
/**
* Test add(name, type, readable, writable) method with 'null' name
*/
public void testAddPropertyNullName3() {
try {
dynaClass.add(null, String.class, true, true);
fail("add(name, type, readable, writable) did not throw UnsupportedOperationException");
} catch (UnsupportedOperationException expected) {
// expected result
}
}
/**
* Test add(name) method when restricted is set to 'true'
*/
public void testAddPropertyRestricted1() {
dynaClass.setRestricted(true);
assertTrue("MutableDynaClass is restricted", dynaClass.isRestricted());
try {
dynaClass.add(testProperty);
fail("add(name) did not throw IllegalStateException");
} catch (IllegalStateException expected) {
// expected result
}
}
/**
* Test add(name, type) method when restricted is set to 'true'
*/
public void testAddPropertyRestricted2() {
dynaClass.setRestricted(true);
assertTrue("MutableDynaClass is restricted", dynaClass.isRestricted());
try {
dynaClass.add(testProperty, String.class);
fail("add(name, type) did not throw IllegalStateException");
} catch (IllegalStateException expected) {
// expected result
}
}
/**
* Test add(name, type, readable, writable) method when restricted is set to 'true'
*/
public void testAddPropertyRestricted3() {
dynaClass.setRestricted(true);
assertTrue("MutableDynaClass is restricted", dynaClass.isRestricted());
try {
dynaClass.add(testProperty, String.class, true, true);
fail("add(name, type, readable, writable) did not throw UnsupportedOperationException");
} catch (UnsupportedOperationException t) {
// expected result
}
}
/**
* Test retrieving a property which doesn't exist (returnNull is 'false')
*/
public void testGetPropertyDoesntExist1() {
dynaClass.setReturnNull(false);
assertFalse("returnNull is 'false'", dynaClass.isReturnNull());
DynaProperty dynaProperty = dynaClass.getDynaProperty(testProperty);
assertEquals("name is correct", testProperty, dynaProperty.getName());
assertEquals("type is correct", Object.class, dynaProperty.getType());
assertFalse("property doesnt exist", dynaClass.isDynaProperty(testProperty));
}
/**
* Test retrieving a property which doesn't exist (returnNull is 'true')
*/
public void testGetPropertyDoesntExist2() {
dynaClass.setReturnNull(true);
assertTrue("returnNull is 'true'", dynaClass.isReturnNull());
assertNull("property is null", dynaClass.getDynaProperty(testProperty));
}
/**
* Test removing a property
*/
public void testRemoveProperty() {
dynaClass.setReturnNull(true);
dynaClass.add(testProperty);
assertTrue("Property exists", dynaClass.isDynaProperty(testProperty));
assertNotNull("property is Not null", dynaClass.getDynaProperty(testProperty));
dynaClass.remove(testProperty);
assertFalse("Property doesn't exist", dynaClass.isDynaProperty(testProperty));
assertNull("property is null", dynaClass.getDynaProperty(testProperty));
}
/**
* Test removing a property, name is null
*/
public void testRemovePropertyNullName() {
try {
dynaClass.remove(null);
fail("remove(null) did not throw IllegalArgumentException");
} catch (IllegalArgumentException expected) {
// expected result
}
}
/**
* Test removing a property, DynaClass is restricted
*/
public void testRemovePropertyRestricted() {
dynaClass.add(testProperty);
assertTrue("Property exists", dynaClass.isDynaProperty(testProperty));
dynaClass.setRestricted(true);
assertTrue("MutableDynaClass is restricted", dynaClass.isRestricted());
try {
dynaClass.remove(testProperty);
fail("remove property when MutableDynaClassis restricted did not throw IllegalStateException");
} catch (IllegalStateException expected) {
// expected result
}
}
/**
* Test removing a property which doesn't exist
*/
public void testRemovePropertyDoesntExist() {
assertFalse("property doesn't exist", dynaClass.isDynaProperty(testProperty));
dynaClass.remove(testProperty);
assertFalse("property still doesn't exist", dynaClass.isDynaProperty(testProperty));
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org