| 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 | } |