001    /**
002     *   GRANITE DATA SERVICES
003     *   Copyright (C) 2006-2013 GRANITE DATA SERVICES S.A.S.
004     *
005     *   This file is part of the Granite Data Services Platform.
006     *
007     *   Granite Data Services is free software; you can redistribute it and/or
008     *   modify it under the terms of the GNU Lesser General Public
009     *   License as published by the Free Software Foundation; either
010     *   version 2.1 of the License, or (at your option) any later version.
011     *
012     *   Granite Data Services is distributed in the hope that it will be useful,
013     *   but WITHOUT ANY WARRANTY; without even the implied warranty of
014     *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
015     *   General Public License for more details.
016     *
017     *   You should have received a copy of the GNU Lesser General Public
018     *   License along with this library; if not, write to the Free Software
019     *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
020     *   USA, or see <http://www.gnu.org/licenses/>.
021     */
022    package org.granite.util;
023    
024    import java.lang.annotation.Annotation;
025    import java.lang.reflect.Field;
026    import java.lang.reflect.InvocationTargetException;
027    import java.lang.reflect.Method;
028    import java.lang.reflect.ParameterizedType;
029    import java.lang.reflect.Type;
030    import java.util.ArrayList;
031    import java.util.List;
032    
033    /**
034     * Reflections class copied from JBoss Seam.
035     * www.seamframework.org 
036     * jboss-seam-2.0.0.GA
037     * Author unattributed
038     *
039     */
040    public class Reflections
041    {
042       
043       public static Object invoke(Method method, Object target, Object... args) throws Exception
044       {
045          try
046          {
047             return method.invoke( target, args );
048          }
049          catch (IllegalArgumentException iae)
050          {
051             String message = "Could not invoke method by reflection: " + toString(method);
052             if (args!=null && args.length>0) 
053             {
054                message += " with parameters: (" + Strings.toClassNameString(", ", args) + ')';
055             }
056             message += " on: " + target.getClass().getName();
057             throw new IllegalArgumentException(message, iae);
058          }
059          catch (InvocationTargetException ite)
060          {
061             if ( ite.getCause() instanceof Exception )
062             {
063                throw (Exception) ite.getCause();
064             }
065             
066             throw ite;
067          }
068       }
069       
070       public static Object get(Field field, Object target) throws Exception
071       {
072          try
073          {
074             return field.get(target);
075          }
076          catch (IllegalArgumentException iae)
077          {
078             String message = "Could not get field value by reflection: " + toString(field) + 
079                " on: " + target.getClass().getName();
080             throw new IllegalArgumentException(message, iae);
081          }
082       }
083       
084       public static void set(Field field, Object target, Object value) throws Exception
085       {
086          try
087          {
088             field.set(target, value);
089          }
090          catch (IllegalArgumentException iae)
091          {
092             // target may be null if field is static so use field.getDeclaringClass() instead
093             String message = "Could not set field value by reflection: " + toString(field) +
094                " on: " + field.getDeclaringClass().getName();
095             if (value==null)
096             {
097                message += " with null value";
098             }
099             else
100             {
101                message += " with value: " + value.getClass();
102             }
103             throw new IllegalArgumentException(message, iae);
104          }
105       }
106       
107       public static Object getAndWrap(Field field, Object target)
108       {
109          try
110          {
111             return get(field, target);
112          }
113          catch (Exception e)
114          {
115             if (e instanceof RuntimeException)
116             {
117                throw (RuntimeException) e;
118             }
119             
120             throw new IllegalArgumentException("exception setting: " + field.getName(), e);
121          }
122       }
123       
124       public static void setAndWrap(Field field, Object target, Object value)
125       {
126          try
127          {
128             set(field, target, value);
129          }
130          catch (Exception e)
131          {
132             if (e instanceof RuntimeException)
133             {
134                throw (RuntimeException) e;
135             }
136             
137             throw new IllegalArgumentException("exception setting: " + field.getName(), e);
138          }
139       }
140       
141       public static Object invokeAndWrap(Method method, Object target, Object... args)
142       {
143          try
144          {
145             return invoke(method, target, args);
146          }
147          catch (Exception e)
148          {
149             if (e instanceof RuntimeException)
150             {
151                throw (RuntimeException) e;
152             }
153             
154             throw new RuntimeException("exception invoking: " + method.getName(), e);
155          }
156       }
157       
158       private static String toString(Method method)
159       {
160          return Strings.unqualify( method.getDeclaringClass().getName() ) + 
161                '.' + 
162                method.getName() + 
163                '(' + 
164                Strings.toString( ", ", method.getParameterTypes() ) + 
165                ')';
166       }
167       
168       private static String toString(Field field)
169       {
170          return Strings.unqualify( field.getDeclaringClass().getName() ) + 
171                '.' + 
172                field.getName();
173       }
174       
175       public static Class<?> classForName(String name) throws ClassNotFoundException
176       {
177          try 
178          {
179             return Thread.currentThread().getContextClassLoader().loadClass(name);
180          }
181          catch (Exception e)
182          {
183             return Class.forName(name);
184          }
185       }
186       
187       /**
188        * Return's true if the class can be loaded using Reflections.classForName()
189        */
190       public static boolean isClassAvailable(String name)
191       {
192          try 
193          {
194             classForName(name);
195          }
196          catch (ClassNotFoundException e) {
197             return false;
198          }
199          return true;
200       }
201    
202       public static Class<?> getCollectionElementType(Type collectionType)
203       {
204          if ( !(collectionType instanceof ParameterizedType) )
205          {
206             throw new IllegalArgumentException("collection type not parameterized");
207          }
208          Type[] typeArguments = ( (ParameterizedType) collectionType ).getActualTypeArguments();
209          if (typeArguments.length==0)
210          {
211             throw new IllegalArgumentException("no type arguments for collection type");
212          }
213          Type typeArgument = typeArguments.length==1 ? typeArguments[0] : typeArguments[1]; //handle Maps
214          if ( !(typeArgument instanceof Class<?>) )
215          {
216             throw new IllegalArgumentException("type argument not a class");
217          }
218          return (Class<?>) typeArgument;
219       }
220       
221       public static Class<?> getMapKeyType(Type collectionType)
222       {
223          if ( !(collectionType instanceof ParameterizedType) )
224          {
225             throw new IllegalArgumentException("collection type not parameterized");
226          }
227          Type[] typeArguments = ( (ParameterizedType) collectionType ).getActualTypeArguments();
228          if (typeArguments.length==0)
229          {
230             throw new IllegalArgumentException("no type arguments for collection type");
231          }
232          Type typeArgument = typeArguments[0];
233          if ( !(typeArgument instanceof Class<?>) )
234          {
235             throw new IllegalArgumentException("type argument not a class");
236          }
237          return (Class<?>) typeArgument;
238       }
239       
240       public static Method getSetterMethod(Class<?> clazz, String name)
241       {
242          Method[] methods = clazz.getMethods();
243          for (Method method: methods)
244          {
245             String methodName = method.getName();
246             if ( methodName.startsWith("set") && method.getParameterTypes().length==1 )
247             {
248                if ( Introspector.decapitalize( methodName.substring(3) ).equals(name) )
249                {
250                   return method;
251                }
252             }
253          }
254          throw new IllegalArgumentException("no such setter method: " + clazz.getName() + '.' + name);
255       }
256       
257       public static Method getGetterMethod(Class<?> clazz, String name) {
258           Method[] methods = clazz.getMethods();
259           for (Method method : methods) {
260               String methodName = method.getName();
261               if (methodName.matches("^(get|is).*") && method.getParameterTypes().length == 0) {
262                   int idx = methodName.startsWith("get") ? 3 : 2;
263                   if (Introspector.decapitalize(methodName.substring(idx)).equals(name))
264                       return method;
265               }
266           }
267           throw new IllegalArgumentException("no such getter method: " + clazz.getName() + '.' + name);
268        }
269       
270       /**
271        * Get all the getter methods annotated with the given annotation. Returns an empty list if
272        * none are found
273        */
274       public static List<Method> getGetterMethods(Class<?> clazz, Class<? extends Annotation> annotation) 
275       {
276          List<Method> methods = new ArrayList<Method>();
277          for (Method method : clazz.getMethods())
278          {
279             if (method.isAnnotationPresent(annotation))
280             {
281                methods.add(method);
282             }
283          }
284          return methods;
285       }
286       
287       public static Field getField(Class<?> clazz, String name)
288       {
289          for ( Class<?> superClass = clazz; superClass!=Object.class; superClass=superClass.getSuperclass() )
290          {
291             try
292             {
293                return superClass.getDeclaredField(name);
294             }
295             catch (NoSuchFieldException nsfe) {}
296          }
297          throw new IllegalArgumentException("no such field: " + clazz.getName() + '.' + name);
298       }
299       
300       /**
301        * Get all the fields which are annotated with the given annotation. Returns an empty list
302        * if none are found
303        */
304       public static List<Field> getFields(Class<?> clazz, Class<? extends Annotation> annotation)
305       {
306          List<Field> fields = new ArrayList<Field>();
307          for (Class<?> superClass = clazz; superClass!=Object.class; superClass=superClass.getSuperclass())
308          {
309             for (Field field : superClass.getDeclaredFields())
310             {
311                if (field.isAnnotationPresent(annotation))
312                {
313                   fields.add(field);
314                }
315             }
316          }
317          return fields;
318       }
319    
320       public static Method getMethod(Annotation annotation, String name)
321       {
322          try
323          {
324             return annotation.annotationType().getMethod(name);
325          }
326          catch (NoSuchMethodException nsme)
327          {
328             return null;
329          }
330       }
331       
332       public static boolean isInstanceOf(Class<?> clazz, String name)
333       {
334          if (name == null)
335          {
336             throw new IllegalArgumentException("name cannot be null");
337          }
338          for (Class<?> c = clazz; c != Object.class; c = c.getSuperclass())
339          {
340             if (name.equals(c.getName()))
341             {
342                return true;
343             }
344          }
345          for (Class<?> c : clazz.getInterfaces())
346          {
347             if (name.equals(c.getName()))
348             {
349                return true;
350             }
351          }
352          return false;
353       }
354    
355            
356       public static Object get(Object object, String fieldName) {
357               Field field = null;
358               for (Class<?> superClass = object.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) {
359                       try {
360                               field = superClass.getDeclaredField(fieldName);
361                                    break;
362                       }
363                       catch (NoSuchFieldException nsfe) {
364                       }
365               }
366               if (field == null)
367                       throw new RuntimeException("Could not find field " + fieldName + " of " + object);
368               field.setAccessible(true);
369               try {
370                       return field.get(object);
371               }
372               catch (Exception e) {
373                       throw new RuntimeException("Could not get field " + fieldName + " of " + object, e);
374               }
375       }
376       
377       @SuppressWarnings("unchecked")
378       public static <T> T get(Object object, String fieldName, Class<T> valueClass) {
379               Field field = null;
380               for (Class<?> superClass = object.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) {
381                       try {
382                               field = superClass.getDeclaredField(fieldName);
383                               break;
384                       }
385                       catch (NoSuchFieldException nsfe) {
386                       }
387               }
388               if (field == null)
389                       throw new RuntimeException("Could not find field " + fieldName + " of " + object);
390               field.setAccessible(true);
391               try {
392                       return (T)field.get(object);
393               }
394               catch (Exception e) {
395                       throw new RuntimeException("Could not get field " + fieldName + " of " + object, e);
396               }
397       }
398    }