View Javadoc

1   /*
2    * $Id: BeanUtils.java 19191 2010-08-25 21:05:23Z tcarlson $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  
11  package org.mule.util;
12  
13  import org.mule.config.i18n.CoreMessages;
14  
15  import java.lang.reflect.Field;
16  import java.lang.reflect.InvocationTargetException;
17  import java.lang.reflect.Method;
18  import java.util.HashMap;
19  import java.util.Iterator;
20  import java.util.Map;
21  
22  import org.apache.commons.logging.Log;
23  import org.apache.commons.logging.LogFactory;
24  
25  /**
26   * <code>BeanUtils</code> provides functions for altering the way commons BeanUtils
27   * works
28   */
29  // @ThreadSafe
30  public class BeanUtils extends org.apache.commons.beanutils.BeanUtils
31  {
32      public static final String SET_PROPERTIES_METHOD = "setProperties";
33  
34      /**
35       * logger used by this class
36       */
37      private static final Log logger = LogFactory.getLog(BeanUtils.class);
38  
39      /**
40       * Exception safe version of BeanUtils.populate()
41       *
42       * @param object      the object to set the properties on
43       * @param props       the map of properties to set
44       * @param logWarnings whether exception warnings should be logged
45       */
46      public static void populateWithoutFail(Object object, Map props, boolean logWarnings)
47      {
48          // Check to see if our object has a setProperties method where the properties
49          // map should be set
50          if (ClassUtils.getMethod(object.getClass(), SET_PROPERTIES_METHOD, new Class[]{Map.class}) != null)
51          {
52              try
53              {
54                  BeanUtils.setProperty(object, "properties", props);
55              }
56              catch (Exception e)
57              {
58                  // this should never happen since we explicitly check for the method
59                  // above
60                  if (logWarnings)
61                  {
62                      logger.warn("Property: " + SET_PROPERTIES_METHOD + "=" + Map.class.getName()
63                              + " not found on object: " + object.getClass().getName());
64                  }
65              }
66          }
67          else
68          {
69              for (Iterator iterator = props.entrySet().iterator(); iterator.hasNext();)
70              {
71                  Map.Entry entry = (Map.Entry) iterator.next();
72  
73                  try
74                  {
75                      BeanUtils.setProperty(object, entry.getKey().toString(), entry.getValue());
76                  }
77                  catch (Exception e)
78                  {
79                      if (logWarnings)
80                      {
81                          logger.warn("Property: " + entry.getKey() + "=" + entry.getValue()
82                                  + " not found on object: " + object.getClass().getName());
83                      }
84                  }
85              }
86          }
87      }
88  
89      /**
90       * This will overlay a map of properties on a bean.  This method will validate that all properties are available
91       * on the bean before setting the properties
92       *
93       * @param bean  the bean on which to set the properties
94       * @param props a Map of properties to set on the bean
95       * @throws IllegalAccessException
96       * @throws InvocationTargetException
97       */
98      public static void populate(Object bean, Map props) throws IllegalAccessException, InvocationTargetException
99      {
100         // Check to see if our object has a setProperties method where the properties
101         // map should be set
102         if (ClassUtils.getMethod(bean.getClass(), SET_PROPERTIES_METHOD, new Class[]{Map.class}) != null)
103         {
104             BeanUtils.setProperty(bean, "properties", props);
105         }
106         else
107         {
108             Map master = describe(bean);
109             for (Iterator iterator = props.keySet().iterator(); iterator.hasNext();)
110             {
111                 Object o = iterator.next();
112                 if (!master.containsKey(o))
113                 {
114                     throw new IllegalArgumentException(CoreMessages.propertyDoesNotExistOnObject(o.toString(), bean).getMessage());
115                 }
116 
117             }
118             org.apache.commons.beanutils.BeanUtils.populate(bean, props);
119         }
120     }
121 
122     /**
123      * The Apache BeanUtils version of this converts all values to String, which is pretty useless, it also includes
124      * stuff not defined by the user
125      *
126      * @param object the object to Describe
127      * @return a map of the properties on the object
128      */
129     public static Map describe(Object object)
130     {
131         Map props = new HashMap(object.getClass().getDeclaredFields().length);
132         for (int i = 0; i < object.getClass().getDeclaredFields().length; i++)
133         {
134             Field field = object.getClass().getDeclaredFields()[i];
135             field.setAccessible(true);
136             try
137             {
138                 props.put(field.getName(), field.get(object));
139             }
140             catch (IllegalAccessException e)
141             {
142                 logger.debug("Unable to read field: " + field.getName() + " on object: " + object);
143             }
144         }
145         return props;
146     }
147 
148     /**
149      * Similar to {@link #describe(Object)} except that it will only populate bean properties where there is a valid
150      * getter and setter method. Basically this method will describe a bean and honour its encapsulation.
151      *
152      * @param object the object to describe
153      * @return a map of published properties
154      */
155     public static Map<String, Object> describeBean(Object object)
156     {
157         Map<String, Object> props = new HashMap<String, Object>();
158         for (int i = 0; i < object.getClass().getMethods().length; i++)
159         {
160             Method method = object.getClass().getMethods()[i];
161             if (method.getName().startsWith("get") || method.getName().startsWith("is"))
162             {
163                 String field = (method.getName().startsWith("is") ? method.getName().substring(2) : method.getName().substring(3));
164                 String setter = "set" + field;
165                 try
166                 {
167                     object.getClass().getMethod(setter, method.getReturnType());
168                 }
169                 catch (NoSuchMethodException e)
170                 {
171                     logger.debug("Ignoring bean property: " + e.getMessage());
172                     continue;
173                 }
174                 field = field.substring(0, 1).toLowerCase() + field.substring(1);
175                 try
176                 {
177                     props.put(field, method.invoke(object));
178                 }
179                 catch (Exception e)
180                 {
181                     logger.debug("unable to call bean method: " + method);
182                 }
183             }
184         }
185         return props;
186     }
187 }