📄 lazydynabean.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.List;
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 java.io.Serializable;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* <p>DynaBean which automatically adds properties to the <code>DynaClass</code>
* 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
* 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 implements DynaBean, Serializable {
/**
* 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 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());
}
/**
* 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 - 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) {
values = newMap();
if (dynaClass instanceof MutableDynaClass) {
this.dynaClass = (MutableDynaClass)dynaClass;
} else {
this.dynaClass = new LazyDynaClass(dynaClass.getName(), dynaClass.getDynaProperties());
}
}
// ------------------- 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 name Name of the property
* @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;
}
/**
* <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.
* @exception IllegalArgumentException if no property name is specified
*/
public Object get(String name) {
if (name == null) {
throw new IllegalArgumentException("No property name specified");
}
// 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;
}
/**
* <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 its not a property, then create default indexed property
if (!isDynaProperty(name)) {
set(name, defaultIndexedProperty(name));
}
// 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 + "]' "
+ dynaClass.getDynaProperty(name).getName());
}
// 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());
}
}
/**
* <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 its not a property, then create default mapped property
if (!isDynaProperty(name)) {
set(name, defaultMappedProperty(name));
}
// 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 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());
}
}
/**
* 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -