    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *      http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 * Unless required by applicable law or agreed to in writing, software
    012 * distributed under the License is distributed on an "AS IS" BASIS,
    013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 * See the License for the specific language governing permissions and
    015 * limitations under the License.
    016 */
    017
    018
    019package org.apache.commons.beanutils;
    020
    021import java.lang.reflect.InvocationTargetException;
    022import java.util.Map;
    023
    024
    025
    026/**
    027 * <p>Utility methods for populating JavaBeans properties via reflection.</p>
    028 *
    029 * <p>The implementations are provided by {@link BeanUtilsBean}.
    030 * These static utility methods use the default instance.
    031 * More sophisticated behaviour can be provided by using a <code>BeanUtilsBean</code> instance.</p>
    032 *
    033 * @version $Id$
    034 * @see BeanUtilsBean
    035 */
    036
    037public class BeanUtils {
    038
    039
    040    // ------------------------------------------------------ Private Variables
    041
    042
    043    /**
    044     * The debugging detail level for this component.
    045     *
    046     * Note that this static variable will have unexpected side-effects if
    047     * this class is deployed in a shared classloader within a container.
    048     * However as it is actually completely ignored by this class due to its
    049     * deprecated status, it doesn't do any actual harm.
    050     *
    051     * @deprecated BeanUtils now uses commons-logging for all log messages.
    052     *             Use your favorite logging tool to configure logging for
    053     *             this class.
    054     */
    055    @Deprecated
    056    private static int debug = 0;
    057
    058    /**
    059     * The <code>debug</code> static property is no longer used
    060     * @return debug property
    061     * @deprecated BeanUtils now uses commons-logging for all log messages.
    062     *             Use your favorite logging tool to configure logging for
    063     *             this class.
    064     */
    065    @Deprecated
    066    public static int getDebug() {
    067        return (debug);
    068    }
    069
    070    /**
    071     * The <code>debug</code> static property is no longer used
    072     * @param newDebug debug property
    073     * @deprecated BeanUtils now uses commons-logging for all log messages.
    074     *             Use your favorite logging tool to configure logging for
    075     *             this class.
    076     */
    077    @Deprecated
    078    public static void setDebug(final int newDebug) {
    079        debug = newDebug;
    080    }
    081
    082    // --------------------------------------------------------- Class Methods
    083
    084
    085    /**
    086     * <p>Clone a bean based on the available property getters and setters,
    087     * even if the bean class itself does not implement Cloneable.</p>
    088     *
    089     * <p>For more details see <code>BeanUtilsBean</code>.</p>
    090     *
    091     * @param bean Bean to be cloned
    092     * @return the cloned bean
    093     *
    094     * @throws IllegalAccessException if the caller does not have
    095     *  access to the property accessor method
    096     * @throws InstantiationException if a new instance of the bean's
    097     *  class cannot be instantiated
    098     * @throws InvocationTargetException if the property accessor method
    099     *  throws an exception
    100     * @throws NoSuchMethodException if an accessor method for this
    101     *  property cannot be found
    102     * @see BeanUtilsBean#cloneBean
    103     */
    104    public static Object cloneBean(final Object bean)
    105            throws IllegalAccessException, InstantiationException,
    106            InvocationTargetException, NoSuchMethodException {
    107
    108        return BeanUtilsBean.getInstance().cloneBean(bean);
    109
    110    }
    111
    112
    113    /**
    114     * <p>Copy property values from the origin bean to the destination bean
    115     * for all cases where the property names are the same.</p>
    116     *
    117     * <p>For more details see <code>BeanUtilsBean</code>.</p>
    118     *
    119     * @param dest Destination bean whose properties are modified
    120     * @param orig Origin bean whose properties are retrieved
    121     *
    122     * @throws IllegalAccessException if the caller does not have
    123     *  access to the property accessor method
    124     * @throws IllegalArgumentException if the <code>dest</code> or
    125     *  <code>orig</code> argument is null or if the <code>dest</code>
    126     *  property type is different from the source type and the relevant
    127     *  converter has not been registered.
    128     * @throws InvocationTargetException if the property accessor method
    129     *  throws an exception
    130     * @see BeanUtilsBean#copyProperties
    131     */
    132    public static void copyProperties(final Object dest, final Object orig)
    133        throws IllegalAccessException, InvocationTargetException {
    134
    135        BeanUtilsBean.getInstance().copyProperties(dest, orig);
    136    }
    137
    138
    139    /**
    140     * <p>Copy the specified property value to the specified destination bean,
    141     * performing any type conversion that is required.</p>
    142     *
    143     * <p>For more details see <code>BeanUtilsBean</code>.</p>
    144     *
    145     * @param bean Bean on which setting is to be performed
    146     * @param name Property name (can be nested/indexed/mapped/combo)
    147     * @param value Value to be set
    148     *
    149     * @throws IllegalAccessException if the caller does not have
    150     *  access to the property accessor method
    151     * @throws InvocationTargetException if the property accessor method
    152     *  throws an exception
    153     * @see BeanUtilsBean#copyProperty
    154     */
    155    public static void copyProperty(final Object bean, final String name, final Object value)
    156        throws IllegalAccessException, InvocationTargetException {
    157
    158        BeanUtilsBean.getInstance().copyProperty(bean, name, value);
    159    }
    160
    161
    162    /**
    163     * <p>Return the entire set of properties for which the specified bean
    164     * provides a read method.</p>
    165     *
    166     * <p>For more details see <code>BeanUtilsBean</code>.</p>
    167     *
    168     * @param bean Bean whose properties are to be extracted
    169     * @return Map of property descriptors
    170     *
    171     * @throws IllegalAccessException if the caller does not have
    172     *  access to the property accessor method
    173     * @throws InvocationTargetException if the property accessor method
    174     *  throws an exception
    175     * @throws NoSuchMethodException if an accessor method for this
    176     *  property cannot be found
    177     * @see BeanUtilsBean#describe
    178     */
    179    public static Map<String, String> describe(final Object bean)
    180            throws IllegalAccessException, InvocationTargetException,
    181            NoSuchMethodException {
    182
    183        return BeanUtilsBean.getInstance().describe(bean);
    184    }
    185
    186
    187    /**
    188     * <p>Return the value of the specified array property of the specified
    189     * bean, as a String array.</p>
    190     *
    191     * <p>For more details see <code>BeanUtilsBean</code>.</p>
    192     *
    193     * @param bean Bean whose property is to be extracted
    194     * @param name Name of the property to be extracted
    195     * @return The array property value
    196     *
    197     * @throws IllegalAccessException if the caller does not have
    198     *  access to the property accessor method
    199     * @throws InvocationTargetException if the property accessor method
    200     *  throws an exception
    201     * @throws NoSuchMethodException if an accessor method for this
    202     *  property cannot be found
    203     * @see BeanUtilsBean#getArrayProperty
    204     */
    205    public static String[] getArrayProperty(final Object bean, final String name)
    206            throws IllegalAccessException, InvocationTargetException,
    207            NoSuchMethodException {
    208
    209        return BeanUtilsBean.getInstance().getArrayProperty(bean, name);
    210    }
    211
    212
    213    /**
    214     * <p>Return the value of the specified indexed property of the specified
    215     * bean, as a String.</p>
    216     *
    217     * <p>For more details see <code>BeanUtilsBean</code>.</p>
    218     *
    219     * @param bean Bean whose property is to be extracted
    220     * @param name <code>propertyname[index]</code> of the property value
    221     *  to be extracted
    222     * @return The indexed property's value, converted to a String
    223     *
    224     * @throws IllegalAccessException if the caller does not have
    225     *  access to the property accessor method
    226     * @throws InvocationTargetException if the property accessor method
    227     *  throws an exception
    228     * @throws NoSuchMethodException if an accessor method for this
    229     *  property cannot be found
    230     * @see BeanUtilsBean#getIndexedProperty(Object, String)
    231     */
    232    public static String getIndexedProperty(final Object bean, final String name)
    233            throws IllegalAccessException, InvocationTargetException,
    234            NoSuchMethodException {
    235
    236        return BeanUtilsBean.getInstance().getIndexedProperty(bean, name);
    237
    238    }
    239
    240
    241    /**
    242     * Return the value of the specified indexed property of the specified
    243     * bean, as a String.  The index is specified as a method parameter and
    244     * must *not* be included in the property name expression
    245     *
    246     * <p>For more details see <code>BeanUtilsBean</code>.</p>
    247     *
    248     * @param bean Bean whose property is to be extracted
    249     * @param name Simple property name of the property value to be extracted
    250     * @param index Index of the property value to be extracted
    251     * @return The indexed property's value, converted to a String
    252     *
    253     * @throws IllegalAccessException if the caller does not have
    254     *  access to the property accessor method
    255     * @throws InvocationTargetException if the property accessor method
    256     *  throws an exception
    257     * @throws NoSuchMethodException if an accessor method for this
    258     *  property cannot be found
    259     * @see BeanUtilsBean#getIndexedProperty(Object, String, int)
    260     */
    261    public static String getIndexedProperty(final Object bean,
    262                                            final String name, final int index)
    263            throws IllegalAccessException, InvocationTargetException,
    264            NoSuchMethodException {
    265
    266        return BeanUtilsBean.getInstance().getIndexedProperty(bean, name, index);
    267
    268    }
    269
    270
    271    /**
    272     * </p>Return the value of the specified indexed property of the specified
    273     * bean, as a String.</p>
    274     *
    275     * <p>For more details see <code>BeanUtilsBean</code>.</p>
    276     *
    277     * @param bean Bean whose property is to be extracted
    278     * @param name <code>propertyname(index)</code> of the property value
    279     *  to be extracted
    280     * @return The mapped property's value, converted to a String
    281     *
    282     * @throws IllegalAccessException if the caller does not have
    283     *  access to the property accessor method
    284     * @throws InvocationTargetException if the property accessor method
    285     *  throws an exception
    286     * @throws NoSuchMethodException if an accessor method for this
    287     *  property cannot be found
    288     * @see BeanUtilsBean#getMappedProperty(Object, String)
    289     */
    290    public static String getMappedProperty(final Object bean, final String name)
    291            throws IllegalAccessException, InvocationTargetException,
    292            NoSuchMethodException {
    293
    294        return BeanUtilsBean.getInstance().getMappedProperty(bean, name);
    295
    296    }
    297
    298
    299    /**
    300     * </p>Return the value of the specified mapped property of the specified
    301     * bean, as a String.</p>
    302     *
    303     * <p>For more details see <code>BeanUtilsBean</code>.</p>
    304     *
    305     * @param bean Bean whose property is to be extracted
    306     * @param name Simple property name of the property value to be extracted
    307     * @param key Lookup key of the property value to be extracted
    308     * @return The mapped property's value, converted to a String
    309     *
    310     * @throws IllegalAccessException if the caller does not have
    311     *  access to the property accessor method
    312     * @throws InvocationTargetException if the property accessor method
    313     *  throws an exception
    314     * @throws NoSuchMethodException if an accessor method for this
    315     *  property cannot be found
    316     * @see BeanUtilsBean#getMappedProperty(Object, String, String)
    317     */
    318    public static String getMappedProperty(final Object bean,
    319                                           final String name, final String key)
    320            throws IllegalAccessException, InvocationTargetException,
    321            NoSuchMethodException {
    322
    323        return BeanUtilsBean.getInstance().getMappedProperty(bean, name, key);
    324
    325    }
    326
    327
    328    /**
    329     * <p>Return the value of the (possibly nested) property of the specified
    330     * name, for the specified bean, as a String.</p>
    331     *
    332     * <p>For more details see <code>BeanUtilsBean</code>.</p>
    333     *
    334     * @param bean Bean whose property is to be extracted
    335     * @param name Possibly nested name of the property to be extracted
    336     * @return The nested property's value, converted to a String
    337     *
    338     * @throws IllegalAccessException if the caller does not have
    339     *  access to the property accessor method
    340     * @throws IllegalArgumentException if a nested reference to a
    341     *  property returns null
    342     * @throws InvocationTargetException if the property accessor method
    343     *  throws an exception
    344     * @throws NoSuchMethodException if an accessor method for this
    345     *  property cannot be found
    346     * @see BeanUtilsBean#getNestedProperty
    347     */
    348    public static String getNestedProperty(final Object bean, final String name)
    349            throws IllegalAccessException, InvocationTargetException,
    350            NoSuchMethodException {
    351
    352        return BeanUtilsBean.getInstance().getNestedProperty(bean, name);
    353
    354    }
    355
    356
    357    /**
    358     * <p>Return the value of the specified property of the specified bean,
    359     * no matter which property reference format is used, as a String.</p>
    360     *
    361     * <p>For more details see <code>BeanUtilsBean</code>.</p>
    362     *
    363     * @param bean Bean whose property is to be extracted
    364     * @param name Possibly indexed and/or nested name of the property
    365     *  to be extracted
    366     * @return The property's value, converted to a String
    367     *
    368     * @throws IllegalAccessException if the caller does not have
    369     *  access to the property accessor method
    370     * @throws InvocationTargetException if the property accessor method
    371     *  throws an exception
    372     * @throws NoSuchMethodException if an accessor method for this
    373     *  property cannot be found
    374     * @see BeanUtilsBean#getProperty
    375     */
    376    public static String getProperty(final Object bean, final String name)
    377            throws IllegalAccessException, InvocationTargetException,
    378            NoSuchMethodException {
    379
    380        return BeanUtilsBean.getInstance().getProperty(bean, name);
    381
    382    }
    383
    384
    385    /**
    386     * <p>Return the value of the specified simple property of the specified
    387     * bean, converted to a String.</p>
    388     *
    389     * <p>For more details see <code>BeanUtilsBean</code>.</p>
    390     *
    391     * @param bean Bean whose property is to be extracted
    392     * @param name Name of the property to be extracted
    393     * @return The property's value, converted to a String
    394     *
    395     * @throws IllegalAccessException if the caller does not have
    396     *  access to the property accessor method
    397     * @throws InvocationTargetException if the property accessor method
    398     *  throws an exception
    399     * @throws NoSuchMethodException if an accessor method for this
    400     *  property cannot be found
    401     * @see BeanUtilsBean#getSimpleProperty
    402     */
    403    public static String getSimpleProperty(final Object bean, final String name)
    404            throws IllegalAccessException, InvocationTargetException,
    405            NoSuchMethodException {
    406
    407        return BeanUtilsBean.getInstance().getSimpleProperty(bean, name);
    408
    409    }
    410
    411
    412    /**
    413     * <p>Populate the JavaBeans properties of the specified bean, based on
    414     * the specified name/value pairs.</p>
    415     *
    416     * <p>For more details see <code>BeanUtilsBean</code>.</p>
    417     *
    418     * @param bean JavaBean whose properties are being populated
    419     * @param properties Map keyed by property name, with the
    420     *  corresponding (String or String[]) value(s) to be set
    421     *
    422     * @throws IllegalAccessException if the caller does not have
    423     *  access to the property accessor method
    424     * @throws InvocationTargetException if the property accessor method
    425     *  throws an exception
    426     * @see BeanUtilsBean#populate
    427     */
    428    public static void populate(final Object bean, final Map<String, ? extends Object> properties)
    429        throws IllegalAccessException, InvocationTargetException {
    430
    431        BeanUtilsBean.getInstance().populate(bean, properties);
    432    }
    433
    434
    435    /**
    436     * <p>Set the specified property value, performing type conversions as
    437     * required to conform to the type of the destination property.</p>
    438     *
    439     * <p>For more details see <code>BeanUtilsBean</code>.</p>
    440     *
    441     * @param bean Bean on which setting is to be performed
    442     * @param name Property name (can be nested/indexed/mapped/combo)
    443     * @param value Value to be set
    444     *
    445     * @throws IllegalAccessException if the caller does not have
    446     *  access to the property accessor method
    447     * @throws InvocationTargetException if the property accessor method
    448     *  throws an exception
    449     * @see BeanUtilsBean#setProperty
    450     */
    451    public static void setProperty(final Object bean, final String name, final Object value)
    452        throws IllegalAccessException, InvocationTargetException {
    453
    454        BeanUtilsBean.getInstance().setProperty(bean, name, value);
    455    }
    456
    457    /**
    458     * If we're running on JDK 1.4 or later, initialize the cause for the given throwable.
    459     *
    460     * @param  throwable The throwable.
    461     * @param  cause     The cause of the throwable.
    462     * @return  true if the cause was initialized, otherwise false.
    463     * @since 1.8.0
    464     */
    465    public static boolean initCause(final Throwable throwable, final Throwable cause) {
    466        return BeanUtilsBean.getInstance().initCause(throwable, cause);
    467    }
    468
    469    /**
    470     * Create a cache.
    471     * @param <K> the key type of the cache
    472     * @param <V> the value type of the cache
    473     * @return a new cache
    474     * @since 1.8.0
    475     */
    476    public static <K, V> Map<K, V> createCache() {
    477        return new WeakFastHashMap<K, V>();
    478    }
    479
    480    /**
    481     * Return whether a Map is fast
    482     * @param map The map
    483     * @return Whether it is fast or not.
    484     * @since 1.8.0
    485     */
    486    public static boolean getCacheFast(final Map<?, ?> map) {
    487        if (map instanceof WeakFastHashMap) {
    488            return ((WeakFastHashMap<?, ?>) map).getFast();
    489        } else {
    490            return false;
    491        }
    492    }
    493
    494    /**
    495     * Set whether fast on a Map
    496     * @param map The map
    497     * @param fast Whether it should be fast or not.
    498     * @since 1.8.0
    499     */
    500    public static void setCacheFast(final Map<?, ?> map, final boolean fast) {
    501        if (map instanceof WeakFastHashMap) {
    502            ((WeakFastHashMap<?, ?>)map).setFast(fast);
    503        }
    504    }
    505}