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 }
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
99 Class returnType = method.getReturnType();
100 if (returnType.equals(Void.TYPE))
101 return null;
102
103 if (method.getParameterTypes().length != 0)
104 return null;
105
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
127 if (method.getParameterTypes().length == 0)
128 return null;
129
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
146
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 }