001    package org.granite.util;
002    
003    import java.beans.Introspector;
004    import java.lang.annotation.Annotation;
005    import java.lang.reflect.Field;
006    import java.lang.reflect.InvocationTargetException;
007    import java.lang.reflect.Method;
008    import java.lang.reflect.ParameterizedType;
009    import java.lang.reflect.Type;
010    import java.util.ArrayList;
011    import java.util.List;
012    
013    /**
014     * Reflections class copied from JBoss Seam.
015     * www.seamframework.org 
016     * jboss-seam-2.0.0.GA
017     * Author unattributed
018     *
019     */
020    public class Reflections
021    {
022       
023       public static Object invoke(Method method, Object target, Object... args) throws Exception
024       {
025          try
026          {
027             return method.invoke( target, args );
028          }
029          catch (IllegalArgumentException iae)
030          {
031             String message = "Could not invoke method by reflection: " + toString(method);
032             if (args!=null && args.length>0) 
033             {
034                message += " with parameters: (" + Strings.toClassNameString(", ", args) + ')';
035             }
036             message += " on: " + target.getClass().getName();
037             throw new IllegalArgumentException(message, iae);
038          }
039          catch (InvocationTargetException ite)
040          {
041             if ( ite.getCause() instanceof Exception )
042             {
043                throw (Exception) ite.getCause();
044             }
045             
046             throw ite;
047          }
048       }
049       
050       public static Object get(Field field, Object target) throws Exception
051       {
052          try
053          {
054             return field.get(target);
055          }
056          catch (IllegalArgumentException iae)
057          {
058             String message = "Could not get field value by reflection: " + toString(field) + 
059                " on: " + target.getClass().getName();
060             throw new IllegalArgumentException(message, iae);
061          }
062       }
063       
064       public static void set(Field field, Object target, Object value) throws Exception
065       {
066          try
067          {
068             field.set(target, value);
069          }
070          catch (IllegalArgumentException iae)
071          {
072             // target may be null if field is static so use field.getDeclaringClass() instead
073             String message = "Could not set field value by reflection: " + toString(field) +
074                " on: " + field.getDeclaringClass().getName();
075             if (value==null)
076             {
077                message += " with null value";
078             }
079             else
080             {
081                message += " with value: " + value.getClass();
082             }
083             throw new IllegalArgumentException(message, iae);
084          }
085       }
086       
087       public static Object getAndWrap(Field field, Object target)
088       {
089          try
090          {
091             return get(field, target);
092          }
093          catch (Exception e)
094          {
095             if (e instanceof RuntimeException)
096             {
097                throw (RuntimeException) e;
098             }
099             
100             throw new IllegalArgumentException("exception setting: " + field.getName(), e);
101          }
102       }
103       
104       public static void setAndWrap(Field field, Object target, Object value)
105       {
106          try
107          {
108             set(field, target, value);
109          }
110          catch (Exception e)
111          {
112             if (e instanceof RuntimeException)
113             {
114                throw (RuntimeException) e;
115             }
116             
117             throw new IllegalArgumentException("exception setting: " + field.getName(), e);
118          }
119       }
120       
121       public static Object invokeAndWrap(Method method, Object target, Object... args)
122       {
123          try
124          {
125             return invoke(method, target, args);
126          }
127          catch (Exception e)
128          {
129             if (e instanceof RuntimeException)
130             {
131                throw (RuntimeException) e;
132             }
133             
134             throw new RuntimeException("exception invoking: " + method.getName(), e);
135          }
136       }
137       
138       private static String toString(Method method)
139       {
140          return Strings.unqualify( method.getDeclaringClass().getName() ) + 
141                '.' + 
142                method.getName() + 
143                '(' + 
144                Strings.toString( ", ", method.getParameterTypes() ) + 
145                ')';
146       }
147       
148       private static String toString(Field field)
149       {
150          return Strings.unqualify( field.getDeclaringClass().getName() ) + 
151                '.' + 
152                field.getName();
153       }
154       
155       public static Class<?> classForName(String name) throws ClassNotFoundException
156       {
157          try 
158          {
159             return Thread.currentThread().getContextClassLoader().loadClass(name);
160          }
161          catch (Exception e)
162          {
163             return Class.forName(name);
164          }
165       }
166       
167       /**
168        * Return's true if the class can be loaded using Reflections.classForName()
169        */
170       public static boolean isClassAvailable(String name)
171       {
172          try 
173          {
174             classForName(name);
175          }
176          catch (ClassNotFoundException e) {
177             return false;
178          }
179          return true;
180       }
181    
182       public static Class<?> getCollectionElementType(Type collectionType)
183       {
184          if ( !(collectionType instanceof ParameterizedType) )
185          {
186             throw new IllegalArgumentException("collection type not parameterized");
187          }
188          Type[] typeArguments = ( (ParameterizedType) collectionType ).getActualTypeArguments();
189          if (typeArguments.length==0)
190          {
191             throw new IllegalArgumentException("no type arguments for collection type");
192          }
193          Type typeArgument = typeArguments.length==1 ? typeArguments[0] : typeArguments[1]; //handle Maps
194          if ( !(typeArgument instanceof Class<?>) )
195          {
196             throw new IllegalArgumentException("type argument not a class");
197          }
198          return (Class<?>) typeArgument;
199       }
200       
201       public static Class<?> getMapKeyType(Type collectionType)
202       {
203          if ( !(collectionType instanceof ParameterizedType) )
204          {
205             throw new IllegalArgumentException("collection type not parameterized");
206          }
207          Type[] typeArguments = ( (ParameterizedType) collectionType ).getActualTypeArguments();
208          if (typeArguments.length==0)
209          {
210             throw new IllegalArgumentException("no type arguments for collection type");
211          }
212          Type typeArgument = typeArguments[0];
213          if ( !(typeArgument instanceof Class<?>) )
214          {
215             throw new IllegalArgumentException("type argument not a class");
216          }
217          return (Class<?>) typeArgument;
218       }
219       
220       public static Method getSetterMethod(Class<?> clazz, String name)
221       {
222          Method[] methods = clazz.getMethods();
223          for (Method method: methods)
224          {
225             String methodName = method.getName();
226             if ( methodName.startsWith("set") && method.getParameterTypes().length==1 )
227             {
228                if ( Introspector.decapitalize( methodName.substring(3) ).equals(name) )
229                {
230                   return method;
231                }
232             }
233          }
234          throw new IllegalArgumentException("no such setter method: " + clazz.getName() + '.' + name);
235       }
236       
237       public static Method getGetterMethod(Class<?> clazz, String name) {
238           Method[] methods = clazz.getMethods();
239           for (Method method : methods) {
240               String methodName = method.getName();
241               if (methodName.matches("^(get|is).*") && method.getParameterTypes().length == 0) {
242                   int idx = methodName.startsWith("get") ? 3 : 2;
243                   if (Introspector.decapitalize(methodName.substring(idx)).equals(name))
244                       return method;
245               }
246           }
247           throw new IllegalArgumentException("no such getter method: " + clazz.getName() + '.' + name);
248        }
249       
250       /**
251        * Get all the getter methods annotated with the given annotation. Returns an empty list if
252        * none are found
253        */
254       public static List<Method> getGetterMethods(Class<?> clazz, Class<? extends Annotation> annotation) 
255       {
256          List<Method> methods = new ArrayList<Method>();
257          for (Method method : clazz.getMethods())
258          {
259             if (method.isAnnotationPresent(annotation))
260             {
261                methods.add(method);
262             }
263          }
264          return methods;
265       }
266       
267       public static Field getField(Class<?> clazz, String name)
268       {
269          for ( Class<?> superClass = clazz; superClass!=Object.class; superClass=superClass.getSuperclass() )
270          {
271             try
272             {
273                return superClass.getDeclaredField(name);
274             }
275             catch (NoSuchFieldException nsfe) {}
276          }
277          throw new IllegalArgumentException("no such field: " + clazz.getName() + '.' + name);
278       }
279       
280       /**
281        * Get all the fields which are annotated with the given annotation. Returns an empty list
282        * if none are found
283        */
284       public static List<Field> getFields(Class<?> clazz, Class<? extends Annotation> annotation)
285       {
286          List<Field> fields = new ArrayList<Field>();
287          for (Class<?> superClass = clazz; superClass!=Object.class; superClass=superClass.getSuperclass())
288          {
289             for (Field field : superClass.getDeclaredFields())
290             {
291                if (field.isAnnotationPresent(annotation))
292                {
293                   fields.add(field);
294                }
295             }
296          }
297          return fields;
298       }
299    
300       public static Method getMethod(Annotation annotation, String name)
301       {
302          try
303          {
304             return annotation.annotationType().getMethod(name);
305          }
306          catch (NoSuchMethodException nsme)
307          {
308             return null;
309          }
310       }
311       
312       public static boolean isInstanceOf(Class<?> clazz, String name)
313       {
314          if (name == null)
315          {
316             throw new IllegalArgumentException("name cannot be null");
317          }
318          for (Class<?> c = clazz; c != Object.class; c = c.getSuperclass())
319          {
320             if (name.equals(c.getName()))
321             {
322                return true;
323             }
324          }
325          for (Class<?> c : clazz.getInterfaces())
326          {
327             if (name.equals(c.getName()))
328             {
329                return true;
330             }
331          }
332          return false;
333       }
334    
335    }