View Javadoc

1   /********************************************************************************
2    * $Id: ReflectionUtil.java 410 2008-03-10 18:52:39Z pgmjsd $
3    * $Author: pgmjsd $
4    * $Date: 2008-03-10 14:52:39 -0400 (Mon, 10 Mar 2008) $
5    *
6    * Copyright 2002-2003  YAJUL Developers, Joshua Davis, Kent Vogel.
7    *
8    * Permission is hereby granted, free of charge, to any person obtaining a copy
9    * of this software and associated documentation files (the "Software"), to deal
10   * in the Software without restriction, including without limitation the rights
11   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12   * copies of the Software, and to permit persons to whom the Software is
13   * furnished to do so, subject to the following conditions:
14   *
15   * The above copyright notice and this permission notice shall be included in
16   * all copies or substantial portions of the Software.
17   *
18   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
21   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24   * THE SOFTWARE.
25   *
26   ******************************************************************************/
27  package org.yajul.util;
28  
29  import org.slf4j.Logger;
30  import org.slf4j.LoggerFactory;
31  
32  import java.lang.reflect.Field;
33  import java.lang.reflect.Method;
34  import java.lang.reflect.Modifier;
35  import java.net.URL;
36  import java.util.HashMap;
37  import java.util.Map;
38  
39  /***
40   * Reflection utilities.
41   * User: josh
42   * Date: Nov 16, 2003
43   * Time: 4:45:36 PM
44   */
45  public class ReflectionUtil {
46      private static final Logger log = LoggerFactory.getLogger(ReflectionUtil.class);
47  
48      /***
49       * Returns a map of (Integer->String) from the values of
50       * any static integer constants in the class.
51       *
52       * @param c The class to get the constants from.
53       * @return Map - A map of the constant integer values to their names.
54       * @noinspection EmptyCatchBlock
55       */
56      public static Map<Integer, String> getConstantNameMap(Class c) {
57          Field[] fields = c.getFields();
58          Map<Integer, String> map = new HashMap<Integer, String>();
59          for (int i = 0; i < fields.length; i++) {
60              Field field = fields[i];
61              if (Modifier.isStatic(field.getModifiers())) {
62                  Object value;
63                  try {
64                      value = field.get(null);
65                      if (value instanceof Integer) {
66                          Integer integer = (Integer) value;
67                          map.put(integer, field.getName());
68                      }
69                  }
70                  catch (IllegalArgumentException ignore) {
71                  }
72                  catch (IllegalAccessException ignore) {
73                  }
74              }
75          } // for
76          return map;
77      }
78  
79      /***
80       * Returns true if the method is a property getter.
81       *
82       * @param method The method.
83       * @return true if the method is a property getter.
84       */
85      public static boolean isPropertyGetter(Method method) {
86          return getterPropertyName(method) != null;
87      }
88  
89      /***
90       * Returns the name of the property IFF the method is a property getter, or null if the
91       * method is not a getter.
92       *
93       * @param method The method.
94       * @return the name of the property IFF the method is a property getter, or null if the
95       *         method is not a getter.
96       */
97      public static String getterPropertyName(Method method) {
98          // It can't be a getter if it has a void return type.
99          Class returnType = method.getReturnType();
100         if (returnType.equals(Void.TYPE))
101             return null;
102         // It can't be a getter if it has parameters.
103         if (method.getParameterTypes().length != 0)
104             return null;
105         // It can't be a getter if it's static.
106         if (Modifier.isStatic(method.getModifiers()))
107             return null;
108         String name = method.getName();
109         if (name.startsWith("get") && (!name.equals("getClass")))
110             return methodNameAsPropertyName(name, 3);
111         else if (name.startsWith("is") && (returnType.equals(Boolean.TYPE) || returnType.equals(Boolean.class)))
112             return methodNameAsPropertyName(name, 2);
113         else
114             return null;
115     }
116 
117     /***
118      * Returns the name of the property IFF the method is a property setter, or null if the
119      * method is not a setter.
120      *
121      * @param method The method.
122      * @return the name of the property IFF the method is a property setter, or null if the
123      *         method is not a setter.
124      */
125     public static String setterPropertyName(Method method) {
126         // It can't be a setter if it has no parameters.
127         if (method.getParameterTypes().length == 0)
128             return null;
129         // It can't be a setter if it's static.
130         if (Modifier.isStatic(method.getModifiers()))
131             return null;
132         String name = method.getName();
133         if (name.startsWith("set"))
134             return methodNameAsPropertyName(name, 3);
135         else
136             return null;
137     }
138 
139     private static String methodNameAsPropertyName(String name, int prefixLength) {
140         return Character.toLowerCase(name.charAt(prefixLength)) + name.substring(prefixLength + 1);
141     }
142 
143     public static ClassLoader getCurrentClassLoader() {
144 
145         // lets get a class loader. By using the Thread's class loader, we allow
146         // for more flexability.
147         ClassLoader classLoader;
148         try {
149             classLoader = Thread.currentThread().getContextClassLoader();
150         }
151         catch (SecurityException se) {
152             classLoader = ReflectionUtil.class.getClassLoader();
153             if (log.isDebugEnabled())
154                 log.debug("Unable to use context class loader, using system ClassLoader " + classLoader);
155         }
156 
157         return classLoader;
158     }
159 
160     /***
161      * Creates a new instance of the class using the specified loader.
162      *
163      * @param className The class to instatiate - if null a default will be used
164      * @param loader    The class loader to use when obtaining the instance
165      * @return An Object which is an instance of the class
166      */
167     public static Object createInstance(String className, ClassLoader loader) {
168         try {
169             Class c;
170 
171             if (loader == null)
172                 loader = getCurrentClassLoader();
173 
174             c = loader.loadClass(className);
175 
176             return c.newInstance();
177         }
178         catch (ClassNotFoundException x) {
179             throw new InitializationError("Class " + className
180                     + " not found - " + "please check your classpath", x);
181         }
182         catch (ExceptionInInitializerError eiie) {
183             throw new InitializationError("Class " + className
184                     + " failed to initialize due to: " + eiie.getMessage(), eiie);
185         }
186         catch (InstantiationException ie) {
187             throw new InitializationError("Class " + className
188                     + " could not be instantiated - "
189                     + "is it abstract, an interface, an array, or does it not have an "
190                     + "empty constructor?", ie);
191         }
192         catch (IllegalAccessException iae) {
193             throw new InitializationError("Class " + className
194                     + " could not be accessed - "
195                     + "is it private or is the empty constructor private?",
196                     iae);
197         }
198     }
199 
200     /***
201      * Creates a new instance of the class, throwing an initialization error, if there
202      * was a problem.
203      *
204      * @param className The class name
205      * @return Object - The instance.
206      */
207     public static Object createInstance(String className) {
208         return createInstance(className, getCurrentClassLoader());
209     }
210 
211     /***
212      * Type checked version of create instance using the default class loader.
213      * @param className the class name
214      * @param componentType the type of the instance (e.g. an interface)
215      * @return an instance of the object cast to 'componentType'
216      */
217     public static <T> T createInstance(String className,Class<T> componentType) {
218         return componentType.cast(createInstance(className));
219     }
220 
221     /***
222      * Returns the resource name for the specified class.
223      *
224      * @param c The class.
225      * @return String - The resource name for the class.
226      */
227     public static String getClassResourceName(Class c) {
228         String s = c.getName();
229         return s.replace('.', '/') + ".class";
230     }
231 
232     /***
233      * Returns the URL where the specified class is located in the current classpath.
234      *
235      * @param c The class to look for.
236      * @return URL - The URL where the class was found, using the current class loader.
237      */
238     public static URL findClassURL(Class c) {
239         String resourceName = getClassResourceName(c);
240         ClassLoader loader = getCurrentClassLoader();
241         return loader.getResource(resourceName);
242     }
243 
244     /***
245      * Turns a class file name into a class name.
246      * @param filename the file name
247      * @return the class name.
248      */
249     public static String filenameToClassname(String filename)
250     {
251        return filename.substring( 0, filename.lastIndexOf(".class") )
252              .replace('/', '.').replace('//', '.');
253     }
254 }