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
018package org.apache.commons.beanutils2;
019
020import java.lang.reflect.InvocationTargetException;
021import java.util.Map;
022
023import org.apache.commons.collections4.map.ConcurrentReferenceHashMap;
024
025/**
026 * <p>
027 * Utility methods for populating JavaBeans properties via reflection.
028 * </p>
029 *
030 * <p>
031 * The implementations are provided by {@link BeanUtilsBean}. These static utility methods use the default instance. More sophisticated behavior can be provided
032 * by using a {@code BeanUtilsBean} instance.
033 * </p>
034 *
035 * @see BeanUtilsBean
036 */
037public class BeanUtils {
038
039    /** An empty class array */
040    static final Class<?>[] EMPTY_CLASS_ARRAY = {};
041
042    /** An empty object array */
043    static final Object[] EMPTY_OBJECT_ARRAY = {};
044
045    /**
046     * <p>
047     * Clones a bean based on the available property getters and setters, even if the bean class itself does not implement Cloneable.
048     * </p>
049     *
050     * <p>
051     * For more details see {@code BeanUtilsBean}.
052     * </p>
053     *
054     * @param bean Bean to be cloned
055     * @return the cloned bean
056     * @throws IllegalAccessException    if the caller does not have access to the property accessor method
057     * @throws InstantiationException    if a new instance of the bean's class cannot be instantiated
058     * @throws InvocationTargetException if the property accessor method throws an exception
059     * @throws NoSuchMethodException     if an accessor method for this property cannot be found
060     * @see BeanUtilsBean#cloneBean
061     */
062    public static Object cloneBean(final Object bean) throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException {
063        return BeanUtilsBean.getInstance().cloneBean(bean);
064    }
065
066    /**
067     * <p>
068     * Copies property values from the origin bean to the destination bean for all cases where the property names are the same.
069     * </p>
070     *
071     * <p>
072     * For more details see {@code BeanUtilsBean}.
073     * </p>
074     *
075     * @param dest Destination bean whose properties are modified
076     * @param orig Origin bean whose properties are retrieved
077     * @throws IllegalAccessException    if the caller does not have access to the property accessor method
078     * @throws IllegalArgumentException  if the {@code dest} or {@code orig</code> argument is null or if the <code>dest} property type is different from the
079     *                                   source type and the relevant converter has not been registered.
080     * @throws InvocationTargetException if the property accessor method throws an exception
081     * @see BeanUtilsBean#copyProperties
082     */
083    public static void copyProperties(final Object dest, final Object orig) throws IllegalAccessException, InvocationTargetException {
084        BeanUtilsBean.getInstance().copyProperties(dest, orig);
085    }
086
087    /**
088     * <p>
089     * Copy the specified property value to the specified destination bean, performing any type conversion that is required.
090     * </p>
091     *
092     * <p>
093     * For more details see {@code BeanUtilsBean}.
094     * </p>
095     *
096     * @param bean  Bean on which setting is to be performed
097     * @param name  Property name (can be nested/indexed/mapped/combo)
098     * @param value Value to be set
099     * @throws IllegalAccessException    if the caller does not have access to the property accessor method
100     * @throws InvocationTargetException if the property accessor method throws an exception
101     * @see BeanUtilsBean#copyProperty
102     */
103    public static void copyProperty(final Object bean, final String name, final Object value) throws IllegalAccessException, InvocationTargetException {
104        BeanUtilsBean.getInstance().copyProperty(bean, name, value);
105    }
106
107    /**
108     * Creates a cache.
109     *
110     * @param <K> the key type of the cache
111     * @param <V> the value type of the cache
112     * @return a new cache
113     * @since 1.8.0
114     */
115    public static <K, V> Map<K, V> createCache() {
116        return ConcurrentReferenceHashMap.<K, V>builder().get();
117        // return new ConcurrentHashMap<>();
118    }
119
120    /**
121     * <p>
122     * Return the entire set of properties for which the specified bean provides a read method.
123     * </p>
124     *
125     * <p>
126     * For more details see {@code BeanUtilsBean}.
127     * </p>
128     *
129     * @param bean Bean whose properties are to be extracted
130     * @return Map of property descriptors
131     * @throws IllegalAccessException    if the caller does not have access to the property accessor method
132     * @throws InvocationTargetException if the property accessor method throws an exception
133     * @throws NoSuchMethodException     if an accessor method for this property cannot be found
134     * @see BeanUtilsBean#describe
135     */
136    public static Map<String, String> describe(final Object bean) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
137        return BeanUtilsBean.getInstance().describe(bean);
138    }
139
140    /**
141     * <p>
142     * Return the value of the specified array property of the specified bean, as a String array.
143     * </p>
144     *
145     * <p>
146     * For more details see {@code BeanUtilsBean}.
147     * </p>
148     *
149     * @param bean Bean whose property is to be extracted
150     * @param name Name of the property to be extracted
151     * @return The array property value
152     * @throws IllegalAccessException    if the caller does not have access to the property accessor method
153     * @throws InvocationTargetException if the property accessor method throws an exception
154     * @throws NoSuchMethodException     if an accessor method for this property cannot be found
155     * @see BeanUtilsBean#getArrayProperty
156     */
157    public static String[] getArrayProperty(final Object bean, final String name)
158            throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
159        return BeanUtilsBean.getInstance().getArrayProperty(bean, name);
160    }
161
162    /**
163     * <p>
164     * Return the value of the specified indexed property of the specified bean, as a String.
165     * </p>
166     *
167     * <p>
168     * For more details see {@code BeanUtilsBean}.
169     * </p>
170     *
171     * @param bean Bean whose property is to be extracted
172     * @param name {@code propertyname[index]} of the property value to be extracted
173     * @return The indexed property's value, converted to a String
174     * @throws IllegalAccessException    if the caller does not have access to the property accessor method
175     * @throws InvocationTargetException if the property accessor method throws an exception
176     * @throws NoSuchMethodException     if an accessor method for this property cannot be found
177     * @see BeanUtilsBean#getIndexedProperty(Object, String)
178     */
179    public static String getIndexedProperty(final Object bean, final String name)
180            throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
181        return BeanUtilsBean.getInstance().getIndexedProperty(bean, name);
182
183    }
184
185    /**
186     * Gets the value of the specified indexed property of the specified bean, as a String. The index is specified as a method parameter and must *not* be
187     * included in the property name expression
188     *
189     * <p>
190     * For more details see {@code BeanUtilsBean}.
191     * </p>
192     *
193     * @param bean  Bean whose property is to be extracted
194     * @param name  Simple property name of the property value to be extracted
195     * @param index Index of the property value to be extracted
196     * @return The indexed property's value, converted to a String
197     * @throws IllegalAccessException    if the caller does not have access to the property accessor method
198     * @throws InvocationTargetException if the property accessor method throws an exception
199     * @throws NoSuchMethodException     if an accessor method for this property cannot be found
200     * @see BeanUtilsBean#getIndexedProperty(Object, String, int)
201     */
202    public static String getIndexedProperty(final Object bean, final String name, final int index)
203            throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
204        return BeanUtilsBean.getInstance().getIndexedProperty(bean, name, index);
205
206    }
207
208    /**
209     * <p>
210     * Return the value of the specified indexed property of the specified bean, as a String.
211     * </p>
212     *
213     * <p>
214     * For more details see {@code BeanUtilsBean}.
215     * </p>
216     *
217     * @param bean Bean whose property is to be extracted
218     * @param name {@code propertyname(index)} of the property value to be extracted
219     * @return The mapped property's value, converted to a String
220     * @throws IllegalAccessException    if the caller does not have access to the property accessor method
221     * @throws InvocationTargetException if the property accessor method throws an exception
222     * @throws NoSuchMethodException     if an accessor method for this property cannot be found
223     * @see BeanUtilsBean#getMappedProperty(Object, String)
224     */
225    public static String getMappedProperty(final Object bean, final String name)
226            throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
227        return BeanUtilsBean.getInstance().getMappedProperty(bean, name);
228
229    }
230
231    /**
232     * <p>
233     * Return the value of the specified mapped property of the specified bean, as a String.
234     * </p>
235     *
236     * <p>
237     * For more details see {@code BeanUtilsBean}.
238     * </p>
239     *
240     * @param bean Bean whose property is to be extracted
241     * @param name Simple property name of the property value to be extracted
242     * @param key  Lookup key of the property value to be extracted
243     * @return The mapped property's value, converted to a String
244     * @throws IllegalAccessException    if the caller does not have access to the property accessor method
245     * @throws InvocationTargetException if the property accessor method throws an exception
246     * @throws NoSuchMethodException     if an accessor method for this property cannot be found
247     * @see BeanUtilsBean#getMappedProperty(Object, String, String)
248     */
249    public static String getMappedProperty(final Object bean, final String name, final String key)
250            throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
251        return BeanUtilsBean.getInstance().getMappedProperty(bean, name, key);
252
253    }
254
255    /**
256     * <p>
257     * Return the value of the (possibly nested) property of the specified name, for the specified bean, as a String.
258     * </p>
259     *
260     * <p>
261     * For more details see {@code BeanUtilsBean}.
262     * </p>
263     *
264     * @param bean Bean whose property is to be extracted
265     * @param name Possibly nested name of the property to be extracted
266     * @return The nested property's value, converted to a String
267     * @throws IllegalAccessException    if the caller does not have access to the property accessor method
268     * @throws IllegalArgumentException  if a nested reference to a property returns null
269     * @throws InvocationTargetException if the property accessor method throws an exception
270     * @throws NoSuchMethodException     if an accessor method for this property cannot be found
271     * @see BeanUtilsBean#getNestedProperty
272     */
273    public static String getNestedProperty(final Object bean, final String name)
274            throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
275        return BeanUtilsBean.getInstance().getNestedProperty(bean, name);
276
277    }
278
279    /**
280     * <p>
281     * Return the value of the specified property of the specified bean, no matter which property reference format is used, as a String.
282     * </p>
283     *
284     * <p>
285     * For more details see {@code BeanUtilsBean}.
286     * </p>
287     *
288     * @param bean Bean whose property is to be extracted
289     * @param name Possibly indexed and/or nested name of the property to be extracted
290     * @return The property's value, converted to a String
291     * @throws IllegalAccessException    if the caller does not have access to the property accessor method
292     * @throws InvocationTargetException if the property accessor method throws an exception
293     * @throws NoSuchMethodException     if an accessor method for this property cannot be found
294     * @see BeanUtilsBean#getProperty
295     */
296    public static String getProperty(final Object bean, final String name) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
297        return BeanUtilsBean.getInstance().getProperty(bean, name);
298
299    }
300
301    /**
302     * <p>
303     * Return the value of the specified simple property of the specified bean, converted to a String.
304     * </p>
305     *
306     * <p>
307     * For more details see {@code BeanUtilsBean}.
308     * </p>
309     *
310     * @param bean Bean whose property is to be extracted
311     * @param name Name of the property to be extracted
312     * @return The property's value, converted to a String
313     * @throws IllegalAccessException    if the caller does not have access to the property accessor method
314     * @throws InvocationTargetException if the property accessor method throws an exception
315     * @throws NoSuchMethodException     if an accessor method for this property cannot be found
316     * @see BeanUtilsBean#getSimpleProperty
317     */
318    public static String getSimpleProperty(final Object bean, final String name)
319            throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
320        return BeanUtilsBean.getInstance().getSimpleProperty(bean, name);
321
322    }
323
324    /**
325     * <p>
326     * Populate the JavaBeans properties of the specified bean, based on the specified name/value pairs.
327     * </p>
328     *
329     * <p>
330     * For more details see {@code BeanUtilsBean}.
331     * </p>
332     *
333     * @param bean       JavaBean whose properties are being populated
334     * @param properties Map keyed by property name, with the corresponding (String or String[]) value(s) to be set
335     * @throws IllegalAccessException    if the caller does not have access to the property accessor method
336     * @throws InvocationTargetException if the property accessor method throws an exception
337     * @see BeanUtilsBean#populate
338     */
339    public static void populate(final Object bean, final Map<String, ? extends Object> properties) throws IllegalAccessException, InvocationTargetException {
340        BeanUtilsBean.getInstance().populate(bean, properties);
341    }
342
343    /**
344     * <p>
345     * Set the specified property value, performing type conversions as required to conform to the type of the destination property.
346     * </p>
347     *
348     * <p>
349     * For more details see {@code BeanUtilsBean}.
350     * </p>
351     *
352     * @param bean  Bean on which setting is to be performed
353     * @param name  Property name (can be nested/indexed/mapped/combo)
354     * @param value Value to be set
355     * @throws IllegalAccessException    if the caller does not have access to the property accessor method
356     * @throws InvocationTargetException if the property accessor method throws an exception
357     * @see BeanUtilsBean#setProperty
358     */
359    public static void setProperty(final Object bean, final String name, final Object value) throws IllegalAccessException, InvocationTargetException {
360        BeanUtilsBean.getInstance().setProperty(bean, name, value);
361    }
362}