![JAR search and dependency download from the Maven repository](/logo.png)
org.apache.commons.beanutils2.LazyDynaBean Maven / Gradle / Ivy
Show all versions of commons-beanutils2 Show documentation
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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.beanutils2; import java.io.Serializable; import java.lang.reflect.Array; import java.math.BigDecimal; import java.math.BigInteger; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** *
andDynaBean which automatically adds properties to the {@code DynaClass} * and provides Lazy List and Lazy Map features.
* *DynaBeans deal with three types of properties - simple, indexed and mapped and * have the following {@code get()
set()} methods for * each of these types: *
will automatically add a property to the*
* *- Simple property methods - {@code get(name)} and * {@code set(name, value)}
*- Indexed property methods - {@code get(name, index)} and * {@code set(name, index, value)}
*- Mapped property methods - {@code get(name, key)} and * {@code set(name, key, value)}
*Getting Property Values
*Calling any of the {@code get()} methods, for a property which * doesn't exist, returns {@code null} in this implementation.
* *Setting Simple Properties
*The {@code LazyDynaBean
DynaClass} * if it doesn't exist when the {@code set(name, value)} method is called. * *
type to the* ** DynaBean myBean = new LazyDynaBean(); * myBean.set("myProperty", "myValue"); *
Setting Indexed Properties
*If the property doesn't exist, the {@code LazyDynaBean} will automatically add * a property with an {@code ArrayList
DynaClass} when * the {@code set(name, index, value)} method is called. * It will also instantiate a new {@code ArrayList} and automatically grow * the {@code List} so that it is big enough to accommodate the index being set. * {@code ArrayList} is the default indexed property that LazyDynaBean uses but * this can be easily changed by overriding the {@code defaultIndexedProperty(name)} * method. * *
in the* ** DynaBean myBean = new LazyDynaBean(); * myBean.set("myIndexedProperty", 0, "myValue1"); * myBean.set("myIndexedProperty", 1, "myValue2"); *
If the indexed property does exist in the {@code DynaClass} but is set to * {@code null
LazyDynaBean}, then it will instantiate a * new {@code List
orArray} as specified by the property's type * in the {@code DynaClass
and automatically grow theList} * or {@code Array} so that it is big enough to accommodate the index being set. * *
type to the* ** DynaBean myBean = new LazyDynaBean(); * MutableDynaClass myClass = (MutableDynaClass)myBean.getDynaClass(); * myClass.add("myIndexedProperty", int[].class); * myBean.set("myIndexedProperty", 0, new Integer(10)); * myBean.set("myIndexedProperty", 1, new Integer(20)); *
Setting Mapped Properties
*If the property doesn't exist, the {@code LazyDynaBean} will automatically add * a property with a {@code HashMap
DynaClass} and * instantiate a new {@code HashMap} in the DynaBean when the * {@code set(name, key, value)
method is called.HashMap} is the default * mapped property that LazyDynaBean uses but this can be easily changed by overriding * the {@code defaultMappedProperty(name)} method. * *
in the* ** DynaBean myBean = new LazyDynaBean(); * myBean.set("myMappedProperty", "myKey", "myValue"); *
If the mapped property does exist in the {@code DynaClass} but is set to * {@code null
LazyDynaBean}, then it will instantiate a * new {@code Map
as specified by the property's type in theDynaClass}. * *
have a facility to restrict the* ** DynaBean myBean = new LazyDynaBean(); * MutableDynaClass myClass = (MutableDynaClass)myBean.getDynaClass(); * myClass.add("myMappedProperty", TreeMap.class); * myBean.set("myMappedProperty", "myKey", "myValue"); *
Restricted DynaClass
*{@code MutableDynaClass
DynaClass} * so that its properties cannot be modified. If the {@code MutableDynaClass} is * restricted then calling any of the {@code set()} methods for a property which * doesn't exist will result in a {@code IllegalArgumentException} being thrown. * * @see LazyDynaClass */ public class LazyDynaBean implements DynaBean, Serializable { private static final long serialVersionUID = 1L; /** * Commons Logging */ private transient Log logger = LogFactory.getLog(LazyDynaBean.class); /** BigInteger Zero */ protected static final BigInteger BigInteger_ZERO = new BigInteger("0"); /** BigDecimal Zero */ protected static final BigDecimal BigDecimal_ZERO = new BigDecimal("0"); /** Character Space */ protected static final Character Character_SPACE = Character.valueOf(' '); /** Byte Zero */ protected static final Byte Byte_ZERO = Byte.valueOf((byte)0); /** Short Zero */ protected static final Short Short_ZERO = Short.valueOf((short)0); /** Integer Zero */ protected static final Integer Integer_ZERO = Integer.valueOf(0); /** Long Zero */ protected static final Long Long_ZERO = Long.valueOf(0); /** Float Zero */ protected static final Float Float_ZERO = Float.valueOf((byte)0); /** Double Zero */ protected static final Double Double_ZERO = Double.valueOf((byte)0); /** * The {@code MutableDynaClass} "base class" that this DynaBean * is associated with. */ protected Map
with avalues; /** Map decorator for this DynaBean */ private transient Map mapDecorator; /** * The {@code MutableDynaClass} "base class" that this DynaBean * is associated with. */ protected MutableDynaClass dynaClass; static final LazyDynaBean[] EMPTY_LAZY_DYNA_BEAN_ARRAY = new LazyDynaBean[0]; /** * Constructs a new {@code LazyDynaBean LazyDynaClass} instance. */ public LazyDynaBean() { this(new LazyDynaClass()); } /** * Constructs a new {@code LazyDynaBean
with aLazyDynaClass} instance. * * @param name Name of this DynaBean class */ public LazyDynaBean(final String name) { this(new LazyDynaClass(name)); } /** * Constructs a new {@code DynaBean} associated with the specified * {@code DynaClass
instance - if its not aMutableDynaClass} * then a new {@code LazyDynaClass} is created and the properties copied. * * @param dynaClass The DynaClass we are associated with */ public LazyDynaBean(final DynaClass dynaClass) { values = newMap(); if (dynaClass instanceof MutableDynaClass) { this.dynaClass = (MutableDynaClass)dynaClass; } else { this.dynaClass = new LazyDynaClass(dynaClass.getName(), dynaClass.getDynaProperties()); } } /** *
* Gets a Map representation of this DynaBean. *
* This, for example, could be used in JSTL in the following way to access * a DynaBean's {@code fooProperty}: ** * @return a Map representation of this DynaBean */ public Map
- {@code ${myDynaBean.map.fooProperty}}
getMap() { // cache the Map if (mapDecorator == null) { mapDecorator = new DynaBeanPropertyMapDecorator(this); } return mapDecorator; } /** * Return the size of an indexed or mapped property.
* * @param name Name of the property * @return The indexed or mapped property size * @throws IllegalArgumentException if no property name is specified */ public int size(final String name) { if (name == null) { throw new IllegalArgumentException("No property name specified"); } final 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; } /** * 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 * @return {@code true} if the mapped property contains a value for * the specified key, otherwise {@code false} * * @throws IllegalArgumentException if no property name is specified */ @Override public boolean contains(final String name, final String key) { if (name == null) { throw new IllegalArgumentException("No property name specified"); } final Object value = values.get(name); if (value == null) { return false; } if (value instanceof Map) { return ((Map, ?>) value).containsKey(key); } return false; } /** *Return the value of a simple property with the specified name.
* *N.B. Returns {@code null} if there is no property * of the specified name.
* * @param name Name of the property whose value is to be retrieved. * @return The property's value * @throws IllegalArgumentException if no property name is specified */ @Override public Object get(final 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; } /** *Return the value of an indexed property with the specified name.
* *N.B. Returns {@code null} if there is no 'indexed' * property of the specified name.
* * @param name Name of the property whose value is to be retrieved * @param index Index of the value to be retrieved * @return The indexed property's value * * @throws IllegalArgumentException if the specified property * exists, but is not indexed * @throws IndexOutOfBoundsException if the specified index * is outside the range of the underlying property */ @Override public Object get(final String name, final 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()); } } /** *Return the value of a mapped property with the specified name.
* *N.B. Returns {@code null} if there is no 'mapped' * property of the specified name.
* * @param name Name of the property whose value is to be retrieved * @param key Key of the value to be retrieved * @return The mapped property's value * * @throws IllegalArgumentException if the specified property * exists, but is not mapped */ @Override public Object get(final String name, final String key) { // If its not a property, then create default mapped property if (!isDynaProperty(name)) { set(name, defaultMappedProperty(name)); } // Get the mapped property final 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); } throw new IllegalArgumentException ("Non-mapped property for '" + name + "(" + key + ")'" + mappedProperty.getClass().getName()); } /** * Gets the {@code DynaClass} instance that describes the set of * properties available for this DynaBean. * * @return The associated DynaClass */ @Override public DynaClass getDynaClass() { return 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 * * @throws IllegalArgumentException if there is no property * of the specified name */ @Override public void remove(final String name, final String key) { if (name == null) { throw new IllegalArgumentException("No property name specified"); } final 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()); } } /** * Sets 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 * * @throws IllegalArgumentException if this is not an existing property * name for our DynaClass and the MutableDynaClass is restricted * @throws ConversionException if the specified value cannot be * converted to the type required for this property * @throws NullPointerException if an attempt is made to set a * primitive property to null */ @Override public void set(final String name, final Object value) { // If the property doesn't exist, then add it if (!isDynaProperty(name)) { if (dynaClass.isRestricted()) { throw new IllegalArgumentException ("Invalid property name '" + name + "' (DynaClass is restricted)"); } if (value == null) { dynaClass.add(name); } else { dynaClass.add(name, value.getClass()); } } final 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 values.put(name, value); } /** * Sets 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 * * @throws ConversionException if the specified value cannot be * converted to the type required for this property * @throws IllegalArgumentException if there is no property * of the specified name * @throws IllegalArgumentException if the specified property * exists, but is not indexed * @throws IndexOutOfBoundsException if the specified index * is outside the range of the underlying property */ @Override public void set(final String name, final int index, final Object value) { // 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).getType().getName()); } // Grow indexed property to appropriate size indexedProperty = growIndexedProperty(name, indexedProperty, index); // Set the value in an array if (indexedProperty.getClass().isArray()) { Array.set(indexedProperty, index, value); } else if (indexedProperty instanceof List) { @SuppressWarnings("unchecked") final // Indexed properties are stored in a List