Coverage Report - org.apache.ojb.broker.util.ClassHelper
 
Classes in this File Line Coverage Branch Coverage Complexity
ClassHelper
N/A
N/A
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  
 }