📄 beanutilsbean.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.beans.IndexedPropertyDescriptor;import java.beans.PropertyDescriptor;import java.lang.reflect.Array;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.util.ArrayList;import java.util.Collection;import java.util.HashMap;import java.util.Iterator;import java.util.Map;import java.util.WeakHashMap;import org.apache.commons.collections.FastHashMap;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;/** * <p>JavaBean property population methods.</p> * * <p>This class provides implementations for the utility methods in * {@link BeanUtils}. * Different instances can be used to isolate caches between classloaders * and to vary the value converters registered.</p> * * @author Craig R. McClanahan * @author Ralph Schaer * @author Chris Audley * @author Rey Fran鏾is * @author Gregor Ra齧an * @version $Revision: 1.16 $ $Date: 2004/02/28 13:18:33 $ * @see BeanUtils * @since 1.7 */public class BeanUtilsBean { // ------------------------------------------------------ Private Class Variables /** * Contains <code>BeanUtilsBean</code> instances indexed by context classloader. */ private static final ContextClassLoaderLocal beansByClassLoader = new ContextClassLoaderLocal() { // Creates the default instance used when the context classloader is unavailable protected Object initialValue() { return new BeanUtilsBean(); } }; /** * Gets the instance which provides the functionality for {@link BeanUtils}. * This is a pseudo-singleton - an single instance is provided per (thread) context classloader. * This mechanism provides isolation for web apps deployed in the same container. */ public synchronized static BeanUtilsBean getInstance() { return (BeanUtilsBean) beansByClassLoader.get(); } /** * Sets the instance which provides the functionality for {@link BeanUtils}. * This is a pseudo-singleton - an single instance is provided per (thread) context classloader. * This mechanism provides isolation for web apps deployed in the same container. */ public synchronized static void setInstance(BeanUtilsBean newInstance) { beansByClassLoader.set(newInstance); } // --------------------------------------------------------- Attributes /** * Logging for this instance */ private Log log = LogFactory.getLog(BeanUtils.class); /** Used to perform conversions between object types when setting properties */ private ConvertUtilsBean convertUtilsBean; /** Used to access properties*/ private PropertyUtilsBean propertyUtilsBean; // --------------------------------------------------------- Constuctors /** * <p>Constructs an instance using new property * and conversion instances.</p> */ public BeanUtilsBean() { this(new ConvertUtilsBean(), new PropertyUtilsBean()); } /** * <p>Constructs an instance using given property and conversion instances.</p> * * @param convertUtilsBean use this <code>ConvertUtilsBean</code> * to perform conversions from one object to another * @param propertyUtilsBean use this <code>PropertyUtilsBean</code> * to access properties */ public BeanUtilsBean( ConvertUtilsBean convertUtilsBean, PropertyUtilsBean propertyUtilsBean) { this.convertUtilsBean = convertUtilsBean; this.propertyUtilsBean = propertyUtilsBean; } // --------------------------------------------------------- Public Methods /** * <p>Clone a bean based on the available property getters and setters, * even if the bean class itself does not implement Cloneable.</p> * * <p> * <strong>Note:</strong> this method creates a <strong>shallow</strong> clone. * In other words, any objects referred to by the bean are shared with the clone * rather than being cloned in turn. * </p> * * @param bean Bean to be cloned * * @exception IllegalAccessException if the caller does not have * access to the property accessor method * @exception InstantiationException if a new instance of the bean's * class cannot be instantiated * @exception InvocationTargetException if the property accessor method * throws an exception * @exception NoSuchMethodException if an accessor method for this * property cannot be found */ public Object cloneBean(Object bean) throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException { if (log.isDebugEnabled()) { log.debug("Cloning bean: " + bean.getClass().getName()); } Class clazz = bean.getClass(); Object newBean = null; if (bean instanceof DynaBean) { newBean = ((DynaBean) bean).getDynaClass().newInstance(); } else { newBean = bean.getClass().newInstance(); } getPropertyUtils().copyProperties(newBean, bean); return (newBean); } /** * <p>Copy property values from the origin bean to the destination bean * for all cases where the property names are the same. For each * property, a conversion is attempted as necessary. All combinations of * standard JavaBeans and DynaBeans as origin and destination are * supported. Properties that exist in the origin bean, but do not exist * in the destination bean (or are read-only in the destination bean) are * silently ignored.</p> * * <p>If the origin "bean" is actually a <code>Map</code>, it is assumed * to contain String-valued <strong>simple</strong> property names as the keys, pointing at * the corresponding property values that will be converted (if necessary) * and set in the destination bean. <strong>Note</strong> that this method * is intended to perform a "shallow copy" of the properties and so complex * properties (for example, nested ones) will not be copied.</p> * * <p>This method differs from <code>populate()</code>, which * was primarily designed for populating JavaBeans from the map of request * parameters retrieved on an HTTP request, is that no scalar->indexed * or indexed->scalar manipulations are performed. If the origin property * is indexed, the destination property must be also.</p> * * <p>If you know that no type conversions are required, the * <code>copyProperties()</code> method in {@link PropertyUtils} will * execute faster than this method.</p> * * <p><strong>FIXME</strong> - Indexed and mapped properties that do not * have getter and setter methods for the underlying array or Map are not * copied by this method.</p> * * @param dest Destination bean whose properties are modified * @param orig Origin bean whose properties are retrieved * * @exception IllegalAccessException if the caller does not have * access to the property accessor method * @exception IllegalArgumentException if the <code>dest</code> or * <code>orig</code> argument is null * @exception InvocationTargetException if the property accessor method * throws an exception */ public void copyProperties(Object dest, Object orig) throws IllegalAccessException, InvocationTargetException { // Validate existence of the specified beans if (dest == null) { throw new IllegalArgumentException ("No destination bean specified"); } if (orig == null) { throw new IllegalArgumentException("No origin bean specified"); } if (log.isDebugEnabled()) { log.debug("BeanUtils.copyProperties(" + dest + ", " + orig + ")"); } // Copy the properties, converting as necessary if (orig instanceof DynaBean) { DynaProperty origDescriptors[] = ((DynaBean) orig).getDynaClass().getDynaProperties(); for (int i = 0; i < origDescriptors.length; i++) { String name = origDescriptors[i].getName(); if (getPropertyUtils().isWriteable(dest, name)) { Object value = ((DynaBean) orig).get(name); copyProperty(dest, name, value); } } } else if (orig instanceof Map) { Iterator names = ((Map) orig).keySet().iterator(); while (names.hasNext()) { String name = (String) names.next(); if (getPropertyUtils().isWriteable(dest, name)) { Object value = ((Map) orig).get(name); copyProperty(dest, name, value); } } } else /* if (orig is a standard JavaBean) */ { PropertyDescriptor origDescriptors[] = getPropertyUtils().getPropertyDescriptors(orig); for (int i = 0; i < origDescriptors.length; i++) { String name = origDescriptors[i].getName(); if ("class".equals(name)) { continue; // No point in trying to set an object's class } if (getPropertyUtils().isReadable(orig, name) && getPropertyUtils().isWriteable(dest, name)) { try { Object value = getPropertyUtils().getSimpleProperty(orig, name); copyProperty(dest, name, value); } catch (NoSuchMethodException e) { ; // Should not happen } } } } } /** * <p>Copy the specified property value to the specified destination bean, * performing any type conversion that is required. If the specified * bean does not have a property of the specified name, or the property * is read only on the destination bean, return without * doing anything. If you have custom destination property types, register * {@link Converter}s for them by calling the <code>register()</code> * method of {@link ConvertUtils}.</p> * * <p><strong>IMPLEMENTATION RESTRICTIONS</strong>:</p> * <ul> * <li>Does not support destination properties that are indexed, * but only an indexed setter (as opposed to an array setter) * is available.</li> * <li>Does not support destination properties that are mapped, * but only a keyed setter (as opposed to a Map setter) * is available.</li> * <li>The desired property type of a mapped setter cannot be * determined (since Maps support any data type), so no conversion * will be performed.</li> * </ul> * * @param bean Bean on which setting is to be performed * @param name Property name (can be nested/indexed/mapped/combo) * @param value Value to be set * * @exception IllegalAccessException if the caller does not have * access to the property accessor method * @exception InvocationTargetException if the property accessor method * throws an exception */ public void copyProperty(Object bean, String name, Object value) throws IllegalAccessException, InvocationTargetException { // Trace logging (if enabled) if (log.isTraceEnabled()) { StringBuffer sb = new StringBuffer(" copyProperty("); sb.append(bean); sb.append(", "); sb.append(name); sb.append(", "); if (value == null) { sb.append("<NULL>"); } else if (value instanceof String) { sb.append((String) value); } else if (value instanceof String[]) { String values[] = (String[]) value; sb.append('['); for (int i = 0; i < values.length; i++) { if (i > 0) { sb.append(','); } sb.append(values[i]); } sb.append(']'); } else { sb.append(value.toString()); } sb.append(')'); log.trace(sb.toString()); } // Resolve any nested expression to get the actual target bean Object target = bean; int delim = name.lastIndexOf(PropertyUtils.NESTED_DELIM); if (delim >= 0) { try { target = getPropertyUtils().getProperty(bean, name.substring(0, delim)); } catch (NoSuchMethodException e) { return; // Skip this property setter } name = name.substring(delim + 1); if (log.isTraceEnabled()) { log.trace(" Target bean = " + target); log.trace(" Target name = " + name); } } // Declare local variables we will require String propName = null; // Simple name of target property Class type = null; // Java type of target property int index = -1; // Indexed subscript value (if any) String key = null; // Mapped key value (if any) // Calculate the target property name, index, and key values propName = name; int i = propName.indexOf(PropertyUtils.INDEXED_DELIM);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -