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}