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 * @author Craig R. McClanahan
034 * @author Ralph Schaer
035 * @author Chris Audley
036 * @author Rey Francois
037 * @author Gregor Rayman
038 * @version $Revision: 690380 $ $Date: 2008-08-29 21:04:38 +0100 (Fri, 29 Aug 2008) $
039 * @see BeanUtilsBean
040 */
041
042public class BeanUtils {
043
044
045    // ------------------------------------------------------ Private Variables
046
047
048    /**
049     * The debugging detail level for this component.
050     * 
051     * Note that this static variable will have unexpected side-effects if
052     * this class is deployed in a shared classloader within a container.
053     * However as it is actually completely ignored by this class due to its
054     * deprecated status, it doesn't do any actual harm.
055     * 
056     * @deprecated BeanUtils now uses commons-logging for all log messages.
057     *             Use your favorite logging tool to configure logging for
058     *             this class.
059     */
060    private static int debug = 0;
061
062    /**
063     * The <code>debug</code> static property is no longer used
064     * @return debug property
065     * @deprecated BeanUtils now uses commons-logging for all log messages.
066     *             Use your favorite logging tool to configure logging for
067     *             this class.
068     */
069    public static int getDebug() {
070        return (debug);
071    }
072
073    /**
074     * The <code>debug</code> static property is no longer used
075     * @param newDebug debug property
076     * @deprecated BeanUtils now uses commons-logging for all log messages.
077     *             Use your favorite logging tool to configure logging for
078     *             this class.
079     */
080    public static void setDebug(int newDebug) {
081        debug = newDebug;
082    }
083
084    // --------------------------------------------------------- Class Methods
085
086
087    /**
088     * <p>Clone a bean based on the available property getters and setters,
089     * even if the bean class itself does not implement Cloneable.</p>
090     *
091     * <p>For more details see <code>BeanUtilsBean</code>.</p>
092     *
093     * @param bean Bean to be cloned
094     * @return the cloned bean
095     *
096     * @exception IllegalAccessException if the caller does not have
097     *  access to the property accessor method
098     * @exception InstantiationException if a new instance of the bean's
099     *  class cannot be instantiated
100     * @exception InvocationTargetException if the property accessor method
101     *  throws an exception
102     * @exception NoSuchMethodException if an accessor method for this
103     *  property cannot be found
104     * @see BeanUtilsBean#cloneBean
105     */
106    public static Object cloneBean(Object bean)
107            throws IllegalAccessException, InstantiationException,
108            InvocationTargetException, NoSuchMethodException {
109
110        return BeanUtilsBean.getInstance().cloneBean(bean);
111
112    }
113
114
115    /**
116     * <p>Copy property values from the origin bean to the destination bean
117     * for all cases where the property names are the same.</p>
118     *
119     * <p>For more details see <code>BeanUtilsBean</code>.</p>
120     *
121     * @param dest Destination bean whose properties are modified
122     * @param orig Origin bean whose properties are retrieved
123     *
124     * @exception IllegalAccessException if the caller does not have
125     *  access to the property accessor method
126     * @exception IllegalArgumentException if the <code>dest</code> or
127     *  <code>orig</code> argument is null or if the <code>dest</code> 
128     *  property type is different from the source type and the relevant
129     *  converter has not been registered.
130     * @exception InvocationTargetException if the property accessor method
131     *  throws an exception
132     * @see BeanUtilsBean#copyProperties
133     */
134    public static void copyProperties(Object dest, Object orig)
135        throws IllegalAccessException, InvocationTargetException {
136        
137        BeanUtilsBean.getInstance().copyProperties(dest, orig);
138    }
139
140
141    /**
142     * <p>Copy the specified property value to the specified destination bean,
143     * performing any type conversion that is required.</p>    
144     *
145     * <p>For more details see <code>BeanUtilsBean</code>.</p>
146     *
147     * @param bean Bean on which setting is to be performed
148     * @param name Property name (can be nested/indexed/mapped/combo)
149     * @param value Value to be set
150     *
151     * @exception IllegalAccessException if the caller does not have
152     *  access to the property accessor method
153     * @exception InvocationTargetException if the property accessor method
154     *  throws an exception
155     * @see BeanUtilsBean#copyProperty     
156     */
157    public static void copyProperty(Object bean, String name, Object value)
158        throws IllegalAccessException, InvocationTargetException {
159
160        BeanUtilsBean.getInstance().copyProperty(bean, name, value);
161    }
162
163
164    /**
165     * <p>Return the entire set of properties for which the specified bean
166     * provides a read method.</p>
167     *
168     * <p>For more details see <code>BeanUtilsBean</code>.</p>
169     *
170     * @param bean Bean whose properties are to be extracted
171     * @return Map of property descriptors
172     *
173     * @exception IllegalAccessException if the caller does not have
174     *  access to the property accessor method
175     * @exception InvocationTargetException if the property accessor method
176     *  throws an exception
177     * @exception NoSuchMethodException if an accessor method for this
178     *  property cannot be found
179     * @see BeanUtilsBean#describe 
180     */
181    public static Map describe(Object bean)
182            throws IllegalAccessException, InvocationTargetException,
183            NoSuchMethodException {
184
185        return BeanUtilsBean.getInstance().describe(bean);
186    }
187
188
189    /**
190     * <p>Return the value of the specified array property of the specified
191     * bean, as a String array.</p>
192     *
193     * <p>For more details see <code>BeanUtilsBean</code>.</p>
194     *
195     * @param bean Bean whose property is to be extracted
196     * @param name Name of the property to be extracted
197     * @return The array property value
198     *
199     * @exception IllegalAccessException if the caller does not have
200     *  access to the property accessor method
201     * @exception InvocationTargetException if the property accessor method
202     *  throws an exception
203     * @exception NoSuchMethodException if an accessor method for this
204     *  property cannot be found
205     * @see BeanUtilsBean#getArrayProperty 
206     */
207    public static String[] getArrayProperty(Object bean, String name)
208            throws IllegalAccessException, InvocationTargetException,
209            NoSuchMethodException {
210
211        return BeanUtilsBean.getInstance().getArrayProperty(bean, name);
212    }
213
214
215    /**
216     * <p>Return the value of the specified indexed property of the specified
217     * bean, as a String.</p>
218     *
219     * <p>For more details see <code>BeanUtilsBean</code>.</p>
220     *
221     * @param bean Bean whose property is to be extracted
222     * @param name <code>propertyname[index]</code> of the property value
223     *  to be extracted
224     * @return The indexed property's value, converted to a String
225     *
226     * @exception IllegalAccessException if the caller does not have
227     *  access to the property accessor method
228     * @exception InvocationTargetException if the property accessor method
229     *  throws an exception
230     * @exception NoSuchMethodException if an accessor method for this
231     *  property cannot be found
232     * @see BeanUtilsBean#getIndexedProperty(Object, String)
233     */
234    public static String getIndexedProperty(Object bean, String name)
235            throws IllegalAccessException, InvocationTargetException,
236            NoSuchMethodException {
237        
238        return BeanUtilsBean.getInstance().getIndexedProperty(bean, name);
239
240    }
241
242
243    /**
244     * Return the value of the specified indexed property of the specified
245     * bean, as a String.  The index is specified as a method parameter and
246     * must *not* be included in the property name expression
247     *
248     * <p>For more details see <code>BeanUtilsBean</code>.</p>
249     *
250     * @param bean Bean whose property is to be extracted
251     * @param name Simple property name of the property value to be extracted
252     * @param index Index of the property value to be extracted
253     * @return The indexed property's value, converted to a String
254     *
255     * @exception IllegalAccessException if the caller does not have
256     *  access to the property accessor method
257     * @exception InvocationTargetException if the property accessor method
258     *  throws an exception
259     * @exception NoSuchMethodException if an accessor method for this
260     *  property cannot be found
261     * @see BeanUtilsBean#getIndexedProperty(Object, String, int)
262     */
263    public static String getIndexedProperty(Object bean,
264                                            String name, int index)
265            throws IllegalAccessException, InvocationTargetException,
266            NoSuchMethodException {
267
268        return BeanUtilsBean.getInstance().getIndexedProperty(bean, name, index);
269
270    }
271
272
273    /**
274     * </p>Return the value of the specified indexed property of the specified
275     * bean, as a String.</p>
276     *
277     * <p>For more details see <code>BeanUtilsBean</code>.</p>
278     *
279     * @param bean Bean whose property is to be extracted
280     * @param name <code>propertyname(index)</code> of the property value
281     *  to be extracted
282     * @return The mapped property's value, converted to a String
283     *
284     * @exception IllegalAccessException if the caller does not have
285     *  access to the property accessor method
286     * @exception InvocationTargetException if the property accessor method
287     *  throws an exception
288     * @exception NoSuchMethodException if an accessor method for this
289     *  property cannot be found
290     * @see BeanUtilsBean#getMappedProperty(Object, String)
291     */
292    public static String getMappedProperty(Object bean, String name)
293            throws IllegalAccessException, InvocationTargetException,
294            NoSuchMethodException {
295
296        return BeanUtilsBean.getInstance().getMappedProperty(bean, name);
297
298    }
299
300
301    /**
302     * </p>Return the value of the specified mapped property of the specified
303     * bean, as a String.</p>
304     *
305     * <p>For more details see <code>BeanUtilsBean</code>.</p>
306     *
307     * @param bean Bean whose property is to be extracted
308     * @param name Simple property name of the property value to be extracted
309     * @param key Lookup key of the property value to be extracted
310     * @return The mapped property's value, converted to a String
311     *
312     * @exception IllegalAccessException if the caller does not have
313     *  access to the property accessor method
314     * @exception InvocationTargetException if the property accessor method
315     *  throws an exception
316     * @exception NoSuchMethodException if an accessor method for this
317     *  property cannot be found
318     * @see BeanUtilsBean#getMappedProperty(Object, String, String)
319     */
320    public static String getMappedProperty(Object bean,
321                                           String name, String key)
322            throws IllegalAccessException, InvocationTargetException,
323            NoSuchMethodException {
324
325        return BeanUtilsBean.getInstance().getMappedProperty(bean, name, key);
326
327    }
328
329
330    /**
331     * <p>Return the value of the (possibly nested) property of the specified
332     * name, for the specified bean, as a String.</p>
333     *
334     * <p>For more details see <code>BeanUtilsBean</code>.</p>
335     *
336     * @param bean Bean whose property is to be extracted
337     * @param name Possibly nested name of the property to be extracted
338     * @return The nested property's value, converted to a String
339     *
340     * @exception IllegalAccessException if the caller does not have
341     *  access to the property accessor method
342     * @exception IllegalArgumentException if a nested reference to a
343     *  property returns null
344     * @exception InvocationTargetException if the property accessor method
345     *  throws an exception
346     * @exception NoSuchMethodException if an accessor method for this
347     *  property cannot be found
348     * @see BeanUtilsBean#getNestedProperty
349     */
350    public static String getNestedProperty(Object bean, String name)
351            throws IllegalAccessException, InvocationTargetException,
352            NoSuchMethodException {
353
354        return BeanUtilsBean.getInstance().getNestedProperty(bean, name);
355
356    }
357
358
359    /**
360     * <p>Return the value of the specified property of the specified bean,
361     * no matter which property reference format is used, as a String.</p>
362     *
363     * <p>For more details see <code>BeanUtilsBean</code>.</p>
364     *
365     * @param bean Bean whose property is to be extracted
366     * @param name Possibly indexed and/or nested name of the property
367     *  to be extracted
368     * @return The property's value, converted to a String
369     *
370     * @exception IllegalAccessException if the caller does not have
371     *  access to the property accessor method
372     * @exception InvocationTargetException if the property accessor method
373     *  throws an exception
374     * @exception NoSuchMethodException if an accessor method for this
375     *  property cannot be found
376     * @see BeanUtilsBean#getProperty
377     */
378    public static String getProperty(Object bean, String name)
379            throws IllegalAccessException, InvocationTargetException,
380            NoSuchMethodException {
381
382        return BeanUtilsBean.getInstance().getProperty(bean, name);
383
384    }
385
386
387    /**
388     * <p>Return the value of the specified simple property of the specified
389     * bean, converted to a String.</p>
390     *
391     * <p>For more details see <code>BeanUtilsBean</code>.</p>
392     *
393     * @param bean Bean whose property is to be extracted
394     * @param name Name of the property to be extracted
395     * @return The property's value, converted to a String
396     *
397     * @exception IllegalAccessException if the caller does not have
398     *  access to the property accessor method
399     * @exception InvocationTargetException if the property accessor method
400     *  throws an exception
401     * @exception NoSuchMethodException if an accessor method for this
402     *  property cannot be found
403     * @see BeanUtilsBean#getSimpleProperty
404     */
405    public static String getSimpleProperty(Object bean, String name)
406            throws IllegalAccessException, InvocationTargetException,
407            NoSuchMethodException {
408
409        return BeanUtilsBean.getInstance().getSimpleProperty(bean, name);
410
411    }
412
413
414    /**
415     * <p>Populate the JavaBeans properties of the specified bean, based on
416     * the specified name/value pairs.</p>
417     *
418     * <p>For more details see <code>BeanUtilsBean</code>.</p>
419     *
420     * @param bean JavaBean whose properties are being populated
421     * @param properties Map keyed by property name, with the
422     *  corresponding (String or String[]) value(s) to be set
423     *
424     * @exception IllegalAccessException if the caller does not have
425     *  access to the property accessor method
426     * @exception InvocationTargetException if the property accessor method
427     *  throws an exception
428     * @see BeanUtilsBean#populate
429     */
430    public static void populate(Object bean, Map properties)
431        throws IllegalAccessException, InvocationTargetException {
432        
433        BeanUtilsBean.getInstance().populate(bean, properties);
434    }
435
436
437    /**
438     * <p>Set the specified property value, performing type conversions as
439     * required to conform to the type of the destination property.</p>
440     *
441     * <p>For more details see <code>BeanUtilsBean</code>.</p>
442     *
443     * @param bean Bean on which setting is to be performed
444     * @param name Property name (can be nested/indexed/mapped/combo)
445     * @param value Value to be set
446     *
447     * @exception IllegalAccessException if the caller does not have
448     *  access to the property accessor method
449     * @exception InvocationTargetException if the property accessor method
450     *  throws an exception
451     * @see BeanUtilsBean#setProperty
452     */
453    public static void setProperty(Object bean, String name, Object value)
454        throws IllegalAccessException, InvocationTargetException {
455
456        BeanUtilsBean.getInstance().setProperty(bean, name, value);
457    }
458
459    /** 
460     * If we're running on JDK 1.4 or later, initialize the cause for the given throwable.
461     * 
462     * @param  throwable The throwable.
463     * @param  cause     The cause of the throwable.
464     * @return  true if the cause was initialized, otherwise false.
465     * @since 1.8.0
466     */
467    public static boolean initCause(Throwable throwable, Throwable cause) {
468        return BeanUtilsBean.getInstance().initCause(throwable, cause);
469    }
470
471    /**
472     * Create a cache.
473     * @return a new cache
474     * @since 1.8.0
475     */
476    public static Map createCache() {
477        return new WeakFastHashMap();
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(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(Map map, boolean fast) {
501        if (map instanceof WeakFastHashMap) {
502            ((WeakFastHashMap)map).setFast(fast);
503        }
504    }
505}