View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.extensions.validator.util;
20  
21  import java.beans.BeanInfo;
22  import java.beans.IntrospectionException;
23  import java.beans.Introspector;
24  import java.beans.PropertyDescriptor;
25  import java.lang.reflect.Field;
26  import java.lang.reflect.InvocationTargetException;
27  import java.lang.reflect.Method;
28  import java.util.StringTokenizer;
29  import java.util.logging.Level;
30  import java.util.logging.Logger;
31  
32  import org.apache.myfaces.extensions.validator.core.ExtValContext;
33  import org.apache.myfaces.extensions.validator.core.storage.PropertyStorage;
34  import org.apache.myfaces.extensions.validator.internal.UsageCategory;
35  import org.apache.myfaces.extensions.validator.internal.UsageInformation;
36  
37  /**
38   * @since 1.x.1
39   */
40  @UsageInformation(UsageCategory.INTERNAL)
41  public class ReflectionUtils
42  {
43      private static final Logger LOGGER = Logger.getLogger(ReflectionUtils.class.getName());
44  
45      public static Method tryToGetMethod(Class targetClass, String targetMethodName)
46      {
47          return tryToGetMethod(targetClass, targetMethodName, null);
48      }
49  
50      public static Method tryToGetMethod(Class targetClass, String targetMethodName, Class... parameterTypes)
51      {
52          try
53          {
54              return getMethod(targetClass, targetMethodName, parameterTypes);
55          }
56          catch (Exception e)
57          {
58              //do nothing - it's just a try
59              return null;
60          }
61      }
62  
63      public static Method getMethod(Class targetClass, String targetMethodName)
64          throws NoSuchMethodException
65      {
66          return getMethod(targetClass, targetMethodName, null);
67      }
68  
69      public static Method getMethod(Class targetClass, String targetMethodName, Class... parameterTypes)
70          throws NoSuchMethodException
71      {
72          Class currentClass = targetClass;
73          Method targetMethod = null;
74  
75          while (!Object.class.getName().equals(currentClass.getName()))
76          {
77              try
78              {
79                  targetMethod = currentClass.getDeclaredMethod(targetMethodName, parameterTypes);
80                  break;
81              }
82              catch (NoSuchMethodException e)
83              {
84                  currentClass = currentClass.getSuperclass();
85              }
86          }
87  
88          if(targetMethod == null)
89          {
90              for (Class currentInterface : targetClass.getInterfaces())
91              {
92                  currentClass = currentInterface;
93  
94                  while (currentClass != null)
95                  {
96                      try
97                      {
98                          targetMethod = currentClass.getDeclaredMethod(targetMethodName, parameterTypes);
99                          break;
100                     }
101                     catch (NoSuchMethodException e)
102                     {
103                         currentClass = currentClass.getSuperclass();
104                     }
105                 }
106             }
107         }
108 
109         if(targetMethod != null)
110         {
111             return targetMethod;
112         }
113 
114         throw new NoSuchMethodException("there is no method with the name '" + targetMethodName + "'" +
115                 " class: " + targetClass.getName());
116     }
117 
118     public static Object tryToInvokeMethod(Object target, Method method)
119     {
120         return tryToInvokeMethod(target, method, null);
121     }
122 
123     public static Object tryToInvokeMethodOfClass(Class target, Method method)
124     {
125         return tryToInvokeMethodOfClass(target, method, null);
126     }
127 
128     public static Object tryToInvokeMethodOfClass(Class target, Method method, Object[] args)
129     {
130         try
131         {
132             return invokeMethodOfClass(target, method, args);
133         }
134         catch (Exception e)
135         {
136             //do nothing - it's just a try
137             return null;
138         }
139     }
140 
141     public static Object invokeMethodOfClass(Class target, Method method)
142         throws IllegalAccessException, InstantiationException, InvocationTargetException
143     {
144         return invokeMethod(target.newInstance(), method, null);
145     }
146 
147     public static Object invokeMethodOfClass(Class target, Method method, Object... args)
148         throws IllegalAccessException, InstantiationException, InvocationTargetException
149     {
150         return invokeMethod(target.newInstance(), method, args);
151     }
152 
153     public static Object tryToInvokeMethod(Object target, Method method, Object... args)
154     {
155         try
156         {
157             return invokeMethod(target, method, args);
158         }
159         catch (Exception e)
160         {
161             //do nothing - it's just a try
162             return null;
163         }
164     }
165 
166     public static Object invokeMethod(Object target, Method method)
167         throws InvocationTargetException, IllegalAccessException
168     {
169         return invokeMethod(target, method, null);
170     }
171 
172     public static Object invokeMethod(Object target, Method method, Object... args)
173         throws InvocationTargetException, IllegalAccessException
174     {
175         method.setAccessible(true);
176         return method.invoke(target, args);
177     }
178 
179     public static Object getBaseOfPropertyChain(Object baseObject, String propertyChain)
180     {
181         StringTokenizer tokenizer = new StringTokenizer(propertyChain, ".");
182 
183         Object currentBase = baseObject;
184         String currentProperty;
185         Method currentMethod;
186 
187         while(tokenizer.hasMoreTokens())
188         {
189             currentProperty = tokenizer.nextToken();
190 
191             //ignore the last property
192             if(!tokenizer.hasMoreTokens())
193             {
194                 break;
195             }
196 
197             //no is - it's only possible at properties not at bean level
198             currentMethod = tryToGetMethod(ProxyUtils.getUnproxiedClass(currentBase.getClass()),
199                 "get" + currentProperty.substring(0, 1).toUpperCase() + currentProperty.substring(1));
200             currentBase = tryToInvokeMethod(currentBase, currentMethod);
201         }
202 
203         return currentBase;
204     }
205 
206     public static PropertyStorage getPropertyStorage()
207     {
208         return ExtValUtils.getStorage(PropertyStorage.class, PropertyStorage.class.getName());
209     }
210 
211     @Deprecated
212     public static Method tryToGetMethodOfProperty(Class entity, String property)
213     {
214         return tryToGetMethodOfProperty(getPropertyStorage(), entity, property);
215     }
216 
217     public static Method tryToGetMethodOfProperty(PropertyStorage storage, Class entity, String property)
218     {
219         if (isCachedMethod(storage, entity, property))
220         {
221             return getCachedMethod(storage, entity, property);
222         }
223 
224         Method method = tryToGetReadMethod(entity, property);
225 
226         tryToCacheMethod(storage, entity, property, method);
227 
228         return method;
229     }
230 
231     @Deprecated
232     public static Field tryToGetFieldOfProperty(Class entity, String property)
233     {
234         return tryToGetFieldOfProperty(getPropertyStorage(), entity, property);
235     }
236 
237     public static Field tryToGetFieldOfProperty(PropertyStorage storage, Class entity, String property)
238     {
239         if (isCachedField(storage, entity, property))
240         {
241             return getCachedField(storage, entity, property);
242         }
243 
244         Field field = null;
245 
246         try
247         {
248             field = entity.getDeclaredField(property);
249         }
250         catch (Exception e)
251         {
252             try
253             {
254                 try
255                 {
256                     field = entity.getDeclaredField("_" + property);
257                 }
258                 catch (Exception e1)
259                 {
260                     if (property.length() > 1
261                             && Character.isUpperCase(property.charAt(0))
262                             && Character.isUpperCase(property.charAt(1)))
263                     {
264                         //don't use Introspector#decapitalize here
265                         field = entity.getDeclaredField(property.substring(0, 1).toLowerCase() + property.substring(1));
266                     }
267                     else
268                     {
269                         field = entity.getDeclaredField(Introspector.decapitalize(property));
270                     }
271                 }
272             }
273             catch (NoSuchFieldException e1)
274             {
275                 LOGGER.log(Level.FINEST, "field " + property + " or _" + property + " not found", e1);
276             }
277         }
278 
279         tryToCacheField(storage, entity, property, field);
280 
281         return field;
282     }
283 
284     private static void tryToCacheField(PropertyStorage storage, Class entity, String property, Field field)
285     {
286         if (!storage.containsField(entity, property))
287         {
288             storage.storeField(entity, property, field);
289         }
290     }
291 
292     private static boolean isCachedField(PropertyStorage storage, Class entity, String property)
293     {
294         return storage.containsField(entity, property);
295     }
296 
297     private static Method tryToGetReadMethod(Class baseBeanClass, String property)
298     {
299         Method method = ReflectionUtils.tryToGetReadMethodViaBeanInfo(baseBeanClass, property);
300 
301         if (method == null)
302         {
303             method = ReflectionUtils.tryToGetReadMethodManually(baseBeanClass, property);
304         }
305         return method;
306     }
307 
308     private static Method tryToGetReadMethodViaBeanInfo(Class entity, String property)
309     {
310         if (useBeanInfo())
311         {
312             try
313             {
314                 BeanInfo beanInfo = Introspector.getBeanInfo(entity);
315                 for (PropertyDescriptor propertyDescriptor : beanInfo
316                         .getPropertyDescriptors())
317                 {
318                     if (property.equals(propertyDescriptor.getName())
319                             && propertyDescriptor.getReadMethod() != null)
320                     {
321                         return propertyDescriptor.getReadMethod();
322                     }
323                 }
324             }
325             catch (IntrospectionException e)
326             {
327                 //do nothing
328             }
329         }
330         return null;
331     }
332 
333     private static boolean useBeanInfo()
334     {
335         return Boolean.TRUE.equals(ExtValContext.getContext().getGlobalProperty(BeanInfo.class.getName()));
336     }
337 
338     private static Method tryToGetReadMethodManually(Class entity, String property)
339     {
340         property = property.substring(0, 1).toUpperCase() + property.substring(1);
341 
342         try
343         {
344             //changed to official bean spec. due to caching there is no performance issue any more
345             return entity.getDeclaredMethod("is" + property);
346         }
347         catch (NoSuchMethodException e)
348         {
349             try
350             {
351                 return entity.getDeclaredMethod("get" + property);
352             }
353             catch (NoSuchMethodException e1)
354             {
355                 LOGGER.finest("method not found - class: " + entity.getName()
356                         + " - methods: " + "get" + property + " " + "is" + property);
357 
358                 return null;
359             }
360         }
361     }
362 
363     private static Field getCachedField(PropertyStorage storage, Class entity, String property)
364     {
365         return storage.getField(entity, property);
366     }
367 
368     private static boolean isCachedMethod(PropertyStorage storage, Class entity, String property)
369     {
370         return storage.containsMethod(entity, property);
371     }
372 
373     private static void tryToCacheMethod(PropertyStorage storage, Class entity, String property, Method method)
374     {
375         if (!storage.containsMethod(entity, property))
376         {
377             storage.storeMethod(entity, property, method);
378         }
379     }
380 
381     private static Method getCachedMethod(PropertyStorage storage, Class entity, String property)
382     {
383         return storage.getMethod(entity, property);
384     }
385 }