package org.smartly.commons.util; import org.smartly.commons.lang.CharEncoding; import java.io.InputStream; import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.net.URL; import java.util.*; @SuppressWarnings("unchecked") public class ClassLoaderUtils { private static final String CHARSET = CharEncoding.getDefault(); private ClassLoaderUtils() { } // -------------------------------------------------------------------- // p u b l i c // -------------------------------------------------------------------- /** * Load a given resource. * <p/> * This method will try to load the resource using the following methods (in order): * <ul> * <li>Thread.currentThread().getContextClassLoader().getResource(name)</li> * <li>{@link ClassLoaderUtils}.class.getClassLoader().getResource(name)</li> * <li>{@link ClassLoaderUtils}.class.getResource(name)</li> * <li>caller.getClass().getResource(name) or, if caller is a Class, * caller.getResource(name)</li> * </ul> * * @param name The name of the resource to load * @param caller The instance or {@link Class} calling this method */ public static URL getResource(final String name, final Object caller) { URL url = getThreadContextLoader().getResource(name); if (url == null) { url = getClassLoader().getResource(name); if (url == null) { url = ClassLoaderUtils.class.getResource(name); if (url == null && caller != null) { Class callingClass = caller.getClass(); if (callingClass == Class.class) { callingClass = (Class) caller; } url = callingClass.getResource(name); } } } return url; } public static Class forName(final String className) throws ClassNotFoundException { return lookupForName(className, getThreadContextLoader()); } public static Class forName(final String className, final ClassLoader loader) throws ClassNotFoundException { return lookupForName(className, loader); } //-- resource Methods --// public static InputStream getResourceAsStream(final String resourcePath) { final ClassLoader cl = getThreadContextLoader(); return cl.getResourceAsStream(resourcePath); } public static InputStream getResourceAsStream(final ClassLoader classLoader, final String resourcePath) { final ClassLoader cl = null != classLoader ? classLoader : getThreadContextLoader(); return cl.getResourceAsStream(resourcePath); } public static InputStream getResourceAsStream(final ClassLoader classLoader, final Class packageClass, final String resourceName) { final ClassLoader cl = null != classLoader ? classLoader : getThreadContextLoader(); final String packagePath = PathUtils.getPackagePath(packageClass); final String resourcePath = PathUtils.join(packagePath, resourceName); return cl.getResourceAsStream(resourcePath); } public static String getResourceAsString(final String resourcePath) { return getString(getResourceAsStream(resourcePath), CHARSET); } public static String getResourceAsString(final ClassLoader classLoader, final String resourcePath) { return getString(getResourceAsStream(classLoader, resourcePath), CHARSET); } public static String getResourceAsString(final ClassLoader classLoader, final Class packageClass, final String resourceName) { return getString(getResourceAsStream(classLoader, packageClass, resourceName), CHARSET); } public static URL getResource(final ClassLoader classLoader, final Class packageClass, final String resourceName) { final ClassLoader cl = null != classLoader ? classLoader : getThreadContextLoader(); final String packagePath = PathUtils.getPackagePath(packageClass); final String resourcePath = PathUtils.join(packagePath, resourceName); return cl.getResource(resourcePath); } public static URL getResource(final String resourcePath) { final ClassLoader cl = getThreadContextLoader(); return cl.getResource(resourcePath); } public static String getResourceAsString(final String resourcePath, final String charset) { return getString(getResourceAsStream(resourcePath), charset); } public static String getResourceAsString(final ClassLoader classLoader, final String resourcePath, final String charset) { return getString(getResourceAsStream(classLoader, resourcePath), charset); } public static String getResourceAsString(final ClassLoader classLoader, final Class packageClass, final String resourceName, final String charset) { return getString(getResourceAsStream(classLoader, packageClass, resourceName), charset); } public static String getString(final InputStream is, final String charset) { if (null != is) { try { return new String(ByteUtils.getBytes(is), charset); } catch (Throwable ignored) { } finally { try { is.close(); } catch (Throwable ignored) { } } } return null; } //-- newInstance Methods --// @SuppressWarnings("unchecked") public static Object newInstance(final String className) throws ClassNotFoundException, InstantiationException, IllegalAccessException { final Class cls = forName(className); if (null != cls) { return cls.newInstance(); } else { throw new ClassNotFoundException("Unable to retrieve class [" + className + "]. Please, check class full name is correct."); } } /** * Creates and intializes a new instance of the specified class with the * specified arguments. * <p/> * <p>Note only public constructors are searched. * * @param cls the class of the instance to create * @param argTypes the argument types of the constructor to inovke * @param args the arguments to initialize the instance * @return the new instance * @throws NoSuchMethodException if a matching method is not found * @throws InstantiationException if the class that declares the * underlying constructor represents an abstract class * @throws java.lang.reflect.InvocationTargetException * if the underlying constructor throws * an exception * @see #newInstance(String, Class[], Object[]) */ @SuppressWarnings("unchecked") public static Object newInstance(final Class cls, final Class[] argTypes, final Object[] args) throws NoSuchMethodException, InstantiationException, InvocationTargetException, IllegalAccessException { final Constructor ctor; if (null == argTypes || argTypes.length == 0) { ctor = cls.getConstructor(); return ctor.newInstance(); } else { ctor = cls.getConstructor(argTypes); return ctor.newInstance(args); } } public static Object newInstance(final Class cls) throws InstantiationException, IllegalAccessException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException { return newInstance(cls, null); } public static Object newInstance(final Class cls, final Object[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException { if (null != args && args.length > 0) { final Class[] types = getTypes(args); final Constructor ctor = cls.getConstructor(types); return ctor.newInstance(args); } return cls.newInstance(); } /** * Creates and initializes a new instance of the specified class name with * the specified arguments. * <p/> * <p>It uses Class.forName to get the class. * * @param clsName the class name of the instance to create * @param argTypes the argument types of the constructor to inovke * @param args the arguments to initialize the instance * @return the new instance * @throws NoSuchMethodException if a matching method is not found * @throws InstantiationException if the class that declares the * underlying constructor represents an abstract class * @throws InvocationTargetException if the underlying constructor throws * an exception * @throws ClassNotFoundException if the specified class name is not a * class * @see #newInstance(Class, Class[], Object[]) */ public static Object newInstance(final String clsName, final Class[] argTypes, final Object[] args) throws NoSuchMethodException, InstantiationException, InvocationTargetException, ClassNotFoundException, IllegalAccessException { final Class aclass = forName(clsName); return null != aclass ? newInstance(aclass, argTypes, args) : null; } public static <T> T optInstance(final String className) { try { return (T) newInstance(className); } catch (Throwable ignored) { } return null; } // -------------------------------------------------------------------- // p r i v a t e // -------------------------------------------------------------------- private final static Map<String, Class> _cache = Collections.synchronizedMap(new HashMap<String, Class>()); private static final ClassLoader getThreadContextLoader() { return Thread.currentThread().getContextClassLoader(); } private static final ClassLoader getClassLoader() { return ClassLoaderUtils.class.getClassLoader(); } private static final ClassLoader getCallerLoader(Object caller) { if (caller instanceof Class) { return ((Class) caller).getClassLoader(); } else { return caller.getClass().getClassLoader(); } } private static Class lookupForName(final String name, final ClassLoader classLoader) throws ClassNotFoundException { final Class result; if (_cache.containsKey(name)) { result = _cache.get(name); } else { // try with primitive final Class primitive = getPrimitiveClass(name); if (primitive != null) { result = primitive; } else { Class tmp = null; if (name.endsWith("[]")) { // special handling for array class names final String elementClassName = name.substring(0, name.length() - "[]".length()); final Class elementClass = lookupForName(elementClassName, classLoader); tmp = Array.newInstance(elementClass, 0).getClass(); } try { if (null == tmp) { tmp = Class.forName(name, true, classLoader); } } catch (Throwable ignored) { } try { if (null == tmp) { tmp = Class.forName(name); } } catch (Throwable ignored) { } try { if (null == tmp) { tmp = classLoader.loadClass(name); } } catch (Throwable ignored) { } result = tmp; } //-- add to cache --// if (null != result) { synchronized (_cache) { _cache.put(name, result); } } } return result; } private static Class getPrimitiveClass(final String name) { // Most class names will be quite long, considering that they // SHOULD sit in a package, so a length check is worthwhile. if (name.length() <= 8) { // could be a primitive - likely final BeanUtils.PrimitiveClasses[] primitives = BeanUtils.PrimitiveClasses.values(); for (final BeanUtils.PrimitiveClasses primitive : primitives) { final Class clazz = primitive.getClass(); if (clazz.getName().equals(name)) { return clazz; } } } return null; } private static Class[] getTypes(final Object[] objects) { final List<Class> result = new LinkedList<Class>(); for (final Object object : objects) { result.add(object.getClass()); } return result.toArray(new Class[result.size()]); } }