Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
ClassHelper |
|
| 2.3684210526315788;2.368 |
1 | package org.apache.ojb.broker.util; | |
2 | ||
3 | /* Copyright 2002-2005 The Apache Software Foundation | |
4 | * | |
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | * you may not use this file except in compliance with the License. | |
7 | * You may obtain a copy of the License at | |
8 | * | |
9 | * http://www.apache.org/licenses/LICENSE-2.0 | |
10 | * | |
11 | * Unless required by applicable law or agreed to in writing, software | |
12 | * distributed under the License is distributed on an "AS IS" BASIS, | |
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | * See the License for the specific language governing permissions and | |
15 | * limitations under the License. | |
16 | */ | |
17 | ||
18 | import java.lang.reflect.InvocationTargetException; | |
19 | import java.lang.reflect.Method; | |
20 | import java.lang.reflect.Field; | |
21 | import java.lang.reflect.Constructor; | |
22 | import java.lang.reflect.Modifier; | |
23 | import java.net.URL; | |
24 | ||
25 | import org.apache.ojb.broker.OJBRuntimeException; | |
26 | import org.apache.ojb.broker.PersistenceBrokerException; | |
27 | import org.apache.ojb.broker.metadata.ClassDescriptor; | |
28 | import org.apache.ojb.broker.metadata.ClassNotPersistenceCapableException; | |
29 | ||
30 | /** | |
31 | * Helper class with static methods for java class, method, and field handling. | |
32 | * | |
33 | * @version $Id: ClassHelper.java,v 1.1 2007-08-24 22:17:36 ewestfal Exp $ | |
34 | */ | |
35 | public class ClassHelper | |
36 | { | |
37 | /** Arguments for invoking a default or no-arg constructor */ | |
38 | private static final Object[] NO_ARGS = {}; | |
39 | /** Parameter types of a default/no-arg constructor */ | |
40 | private static final Class[] NO_ARGS_CLASS = {}; | |
41 | ||
42 | /** The class loader currently used by OJB */ | |
43 | private static ClassLoader _classLoader = null; | |
44 | /** A mutex for changing the class loader */ | |
45 | private static Object _mutex = new Object(); | |
46 | ||
47 | /** | |
48 | * Prevents instatiation. | |
49 | */ | |
50 | private ClassHelper() | |
51 | { | |
52 | } | |
53 | ||
54 | /** | |
55 | * Sets the classloader to be used by OJB. This can be set by external | |
56 | * application that need to pass a specific classloader to OJB. | |
57 | * | |
58 | * @param loader The class loader. If <code>null</code> then OJB will use | |
59 | * the class loader of the current thread | |
60 | */ | |
61 | public static void setClassLoader(ClassLoader loader) | |
62 | { | |
63 | synchronized (_mutex) | |
64 | { | |
65 | _classLoader = loader; | |
66 | } | |
67 | } | |
68 | ||
69 | /** | |
70 | * Returns the class loader currently used by OJB. Defaults to the class loader of | |
71 | * the current thread (<code>Thread.currentThread().getContextClassLoader()</code>) | |
72 | * if not set differently. If class loader is not explicitly set and the loader for | |
73 | * the current thread context is null, the JVM default class loader will be used. | |
74 | * | |
75 | * @return The classloader used by OJB | |
76 | * @see #setClassLoader(ClassLoader) | |
77 | */ | |
78 | public static ClassLoader getClassLoader() | |
79 | { | |
80 | final ClassLoader ojbClassLoader; | |
81 | if (_classLoader != null) | |
82 | { | |
83 | ojbClassLoader = _classLoader; | |
84 | } | |
85 | else | |
86 | { | |
87 | final ClassLoader threadCtxtClassLoader; | |
88 | threadCtxtClassLoader = Thread.currentThread().getContextClassLoader(); | |
89 | if (threadCtxtClassLoader == null) | |
90 | { | |
91 | // mkalen: happens only in "obscure" situations using JNI, revert to system CL | |
92 | ojbClassLoader = ClassLoader.getSystemClassLoader(); | |
93 | } | |
94 | else | |
95 | { | |
96 | ojbClassLoader = threadCtxtClassLoader; | |
97 | } | |
98 | } | |
99 | return ojbClassLoader; | |
100 | } | |
101 | ||
102 | /** | |
103 | * Determines the url of the indicated resource using the currently set class loader. | |
104 | * | |
105 | * @param name The resource name | |
106 | * @return The resource's url | |
107 | */ | |
108 | public static URL getResource(String name) | |
109 | { | |
110 | return getClassLoader().getResource(name); | |
111 | } | |
112 | ||
113 | /** | |
114 | * Retrieves the class object for the given qualified class name. | |
115 | * | |
116 | * @param className The qualified name of the class | |
117 | * @param initialize Whether the class shall be initialized | |
118 | * @return The class object | |
119 | */ | |
120 | public static Class getClass(String className, boolean initialize) throws ClassNotFoundException | |
121 | { | |
122 | return Class.forName(className, initialize, getClassLoader()); | |
123 | } | |
124 | ||
125 | /** | |
126 | * Returns a new instance of the given class, using the default or a no-arg constructor. | |
127 | * | |
128 | * @param target The class to instantiate | |
129 | * @return The instance | |
130 | */ | |
131 | public static Object newInstance(Class target) throws InstantiationException, | |
132 | IllegalAccessException | |
133 | { | |
134 | return target.newInstance(); | |
135 | } | |
136 | ||
137 | /** | |
138 | * Returns a new instance of the given class, using the default or a no-arg constructor. | |
139 | * This method can also use private no-arg constructors if <code>makeAccessible</code> | |
140 | * is set to <code>true</code> (and there are no other security constraints). | |
141 | * | |
142 | * @param target The class to instantiate | |
143 | * @param makeAccessible If the constructor shall be made accessible prior to using it | |
144 | * @return The instance | |
145 | */ | |
146 | public static Object newInstance(Class target, boolean makeAccessible) throws InstantiationException, | |
147 | IllegalAccessException | |
148 | { | |
149 | if (makeAccessible) | |
150 | { | |
151 | try | |
152 | { | |
153 | return newInstance(target, NO_ARGS_CLASS, NO_ARGS, makeAccessible); | |
154 | } | |
155 | catch (InvocationTargetException e) | |
156 | { | |
157 | throw new OJBRuntimeException("Unexpected exception while instantiate class '" | |
158 | + target + "' with default constructor", e); | |
159 | } | |
160 | catch (NoSuchMethodException e) | |
161 | { | |
162 | throw new OJBRuntimeException("Unexpected exception while instantiate class '" | |
163 | + target + "' with default constructor", e); | |
164 | } | |
165 | } | |
166 | else | |
167 | { | |
168 | return target.newInstance(); | |
169 | } | |
170 | } | |
171 | ||
172 | /** | |
173 | * Returns a new instance of the given class, using the constructor with the specified parameter types. | |
174 | * | |
175 | * @param target The class to instantiate | |
176 | * @param types The parameter types | |
177 | * @param args The arguments | |
178 | * @return The instance | |
179 | */ | |
180 | public static Object newInstance(Class target, Class[] types, Object[] args) throws InstantiationException, | |
181 | IllegalAccessException, | |
182 | IllegalArgumentException, | |
183 | InvocationTargetException, | |
184 | NoSuchMethodException, | |
185 | SecurityException | |
186 | { | |
187 | return newInstance(target, types, args, false); | |
188 | } | |
189 | ||
190 | /** | |
191 | * Returns a new instance of the given class, using the constructor with the specified parameter types. | |
192 | * This method can also use private constructors if <code>makeAccessible</code> is set to | |
193 | * <code>true</code> (and there are no other security constraints). | |
194 | * | |
195 | * @param target The class to instantiate | |
196 | * @param types The parameter types | |
197 | * @param args The arguments | |
198 | * @param makeAccessible If the constructor shall be made accessible prior to using it | |
199 | * @return The instance | |
200 | */ | |
201 | public static Object newInstance(Class target, Class[] types, Object[] args, boolean makeAccessible) throws InstantiationException, | |
202 | IllegalAccessException, | |
203 | IllegalArgumentException, | |
204 | InvocationTargetException, | |
205 | NoSuchMethodException, | |
206 | SecurityException | |
207 | { | |
208 | Constructor con; | |
209 | ||
210 | if (makeAccessible) | |
211 | { | |
212 | con = target.getDeclaredConstructor(types); | |
213 | if (makeAccessible && !con.isAccessible()) | |
214 | { | |
215 | con.setAccessible(true); | |
216 | } | |
217 | } | |
218 | else | |
219 | { | |
220 | con = target.getConstructor(types); | |
221 | } | |
222 | return con.newInstance(args); | |
223 | } | |
224 | ||
225 | /** | |
226 | * Determines the method with the specified signature via reflection look-up. | |
227 | * | |
228 | * @param clazz The java class to search in | |
229 | * @param methodName The method's name | |
230 | * @param params The parameter types | |
231 | * @return The method object or <code>null</code> if no matching method was found | |
232 | */ | |
233 | public static Method getMethod(Class clazz, String methodName, Class[] params) | |
234 | { | |
235 | try | |
236 | { | |
237 | return clazz.getMethod(methodName, params); | |
238 | } | |
239 | catch (Exception ignored) | |
240 | {} | |
241 | return null; | |
242 | } | |
243 | ||
244 | /** | |
245 | * Determines the field via reflection look-up. | |
246 | * | |
247 | * @param clazz The java class to search in | |
248 | * @param fieldName The field's name | |
249 | * @return The field object or <code>null</code> if no matching field was found | |
250 | */ | |
251 | public static Field getField(Class clazz, String fieldName) | |
252 | { | |
253 | try | |
254 | { | |
255 | return clazz.getField(fieldName); | |
256 | } | |
257 | catch (Exception ignored) | |
258 | {} | |
259 | return null; | |
260 | } | |
261 | ||
262 | ||
263 | // ******************************************************************* | |
264 | // Convenience methods | |
265 | // ******************************************************************* | |
266 | ||
267 | /** | |
268 | * Convenience method for {@link #getClass(String, boolean) getClass(name, true)} | |
269 | * | |
270 | * @param name The qualified class name | |
271 | * @return The class object | |
272 | */ | |
273 | public static Class getClass(String name) throws ClassNotFoundException | |
274 | { | |
275 | return getClass(name, true); | |
276 | } | |
277 | ||
278 | ||
279 | /** | |
280 | * Returns a new instance of the class with the given qualified name using the default or | |
281 | * or a no-arg constructor. | |
282 | * | |
283 | * @param className The qualified name of the class to instantiate | |
284 | */ | |
285 | public static Object newInstance(String className) throws InstantiationException, | |
286 | IllegalAccessException, | |
287 | ClassNotFoundException | |
288 | { | |
289 | return newInstance(getClass(className)); | |
290 | } | |
291 | ||
292 | /** | |
293 | * Returns a new instance of the class with the given qualified name using the constructor with | |
294 | * the specified signature. | |
295 | * | |
296 | * @param className The qualified name of the class to instantiate | |
297 | * @param types The parameter types | |
298 | * @param args The arguments | |
299 | * @return The instance | |
300 | */ | |
301 | public static Object newInstance(String className, Class[] types, Object[] args) throws InstantiationException, | |
302 | IllegalAccessException, | |
303 | IllegalArgumentException, | |
304 | InvocationTargetException, | |
305 | NoSuchMethodException, | |
306 | SecurityException, | |
307 | ClassNotFoundException | |
308 | { | |
309 | return newInstance(getClass(className), types, args); | |
310 | } | |
311 | ||
312 | /** | |
313 | * Returns a new instance of the given class using the constructor with the specified parameter. | |
314 | * | |
315 | * @param target The class to instantiate | |
316 | * @param type The types of the single parameter of the constructor | |
317 | * @param arg The argument | |
318 | * @return The instance | |
319 | */ | |
320 | public static Object newInstance(Class target, Class type, Object arg) throws InstantiationException, | |
321 | IllegalAccessException, | |
322 | IllegalArgumentException, | |
323 | InvocationTargetException, | |
324 | NoSuchMethodException, | |
325 | SecurityException | |
326 | { | |
327 | return newInstance(target, new Class[]{ type }, new Object[]{ arg }); | |
328 | } | |
329 | ||
330 | /** | |
331 | * Returns a new instance of the class with the given qualified name using the constructor with | |
332 | * the specified parameter. | |
333 | * | |
334 | * @param className The qualified name of the class to instantiate | |
335 | * @param type The types of the single parameter of the constructor | |
336 | * @param arg The argument | |
337 | * @return The instance | |
338 | */ | |
339 | public static Object newInstance(String className, Class type, Object arg) throws InstantiationException, | |
340 | IllegalAccessException, | |
341 | IllegalArgumentException, | |
342 | InvocationTargetException, | |
343 | NoSuchMethodException, | |
344 | SecurityException, | |
345 | ClassNotFoundException | |
346 | { | |
347 | return newInstance(className, new Class[]{type}, new Object[]{arg}); | |
348 | } | |
349 | ||
350 | /** | |
351 | * Determines the method with the specified signature via reflection look-up. | |
352 | * | |
353 | * @param object The instance whose class is searched for the method | |
354 | * @param methodName The method's name | |
355 | * @param params The parameter types | |
356 | * @return A method object or <code>null</code> if no matching method was found | |
357 | */ | |
358 | public static Method getMethod(Object object, String methodName, Class[] params) | |
359 | { | |
360 | return getMethod(object.getClass(), methodName, params); | |
361 | } | |
362 | ||
363 | /** | |
364 | * Determines the method with the specified signature via reflection look-up. | |
365 | * | |
366 | * @param className The qualified name of the searched class | |
367 | * @param methodName The method's name | |
368 | * @param params The parameter types | |
369 | * @return A method object or <code>null</code> if no matching method was found | |
370 | */ | |
371 | public static Method getMethod(String className, String methodName, Class[] params) | |
372 | { | |
373 | try | |
374 | { | |
375 | return getMethod(getClass(className, false), methodName, params); | |
376 | } | |
377 | catch (Exception ignored) | |
378 | {} | |
379 | return null; | |
380 | } | |
381 | ||
382 | /** | |
383 | * Builds a new instance for the class represented by the given class descriptor. | |
384 | * | |
385 | * @param cld The class descriptor | |
386 | * @return The instance | |
387 | */ | |
388 | public static Object buildNewObjectInstance(ClassDescriptor cld) | |
389 | { | |
390 | Object result = null; | |
391 | ||
392 | // If either the factory class and/or factory method is null, | |
393 | // just follow the normal code path and create via constructor | |
394 | if ((cld.getFactoryClass() == null) || (cld.getFactoryMethod() == null)) | |
395 | { | |
396 | try | |
397 | { | |
398 | // 1. create an empty Object (persistent classes need a public default constructor) | |
399 | Constructor con = cld.getZeroArgumentConstructor(); | |
400 | if(con == null) | |
401 | { | |
402 | throw new ClassNotPersistenceCapableException( | |
403 | "A zero argument constructor was not provided! Class was '" + cld.getClassNameOfObject() + "'"); | |
404 | } | |
405 | result = ConstructorHelper.instantiate(con); | |
406 | } | |
407 | catch (InstantiationException e) | |
408 | { | |
409 | throw new ClassNotPersistenceCapableException( | |
410 | "Can't instantiate class '" + cld.getClassNameOfObject()+"'"); | |
411 | } | |
412 | } | |
413 | else | |
414 | { | |
415 | try | |
416 | { | |
417 | // 1. create an empty Object by calling the no-parms factory method | |
418 | Method method = cld.getFactoryMethod(); | |
419 | ||
420 | if (Modifier.isStatic(method.getModifiers())) | |
421 | { | |
422 | // method is static so call it directly | |
423 | result = method.invoke(null, null); | |
424 | } | |
425 | else | |
426 | { | |
427 | // method is not static, so create an object of the factory first | |
428 | // note that this requires a public no-parameter (default) constructor | |
429 | Object factoryInstance = cld.getFactoryClass().newInstance(); | |
430 | ||
431 | result = method.invoke(factoryInstance, null); | |
432 | } | |
433 | } | |
434 | catch (Exception ex) | |
435 | { | |
436 | throw new PersistenceBrokerException("Unable to build object instance of class '" | |
437 | + cld.getClassNameOfObject() + "' from factory:" + cld.getFactoryClass() | |
438 | + "." + cld.getFactoryMethod(), ex); | |
439 | } | |
440 | } | |
441 | return result; | |
442 | } | |
443 | } |