public static Method getClassMethod( String classInternalName, String methodName, String methodDesc) { checkArgNotNull(classInternalName, "classInternalName"); checkArgNotNull(methodName, "methodName"); checkArgNotNull(methodDesc, "methodDesc"); Class<?> clazz = getClassForInternalName(classInternalName); Type[] types = Type.getArgumentTypes(methodDesc); Class<?>[] argTypes = new Class<?>[types.length]; for (int i = 0; i < types.length; i++) { argTypes[i] = getClassForType(types[i]); } Class<?> current = clazz; while (true) { try { return current.getDeclaredMethod(methodName, argTypes); } catch (NoSuchMethodException e) { current = current.getSuperclass(); if (Object.class.equals(current)) { throw new RuntimeException( "Method '" + methodName + "' with descriptor '" + methodDesc + "' not found in '" + clazz + "\' or any superclass", e); } } } }
/** * Returns the class with the given name if it has already been loaded by the given class loader. * Otherwise the method returns null. * * @param className the full name of the class to be loaded * @param classLoader the class loader to use * @return the class instance or null */ public static Class<?> findLoadedClass(String className, ClassLoader classLoader) { checkArgNotNull(className, "className"); checkArgNotNull(classLoader, "classLoader"); try { Class<?> classLoaderBaseClass = Class.forName("java.lang.ClassLoader"); Method findLoadedClassMethod = classLoaderBaseClass.getDeclaredMethod("findLoadedClass", String.class); // protected method invocation findLoadedClassMethod.setAccessible(true); try { return (Class<?>) findLoadedClassMethod.invoke(classLoader, className); } finally { findLoadedClassMethod.setAccessible(false); } } catch (Exception e) { throw new RuntimeException( "Could not determine whether class '" + className + "' has already been loaded", e); } }
/** * Loads the class defined with the given name and bytecode using the given class loader. Since * package and class idendity includes the ClassLoader instance used to load a class we use * reflection on the given class loader to define generated classes. If we used our own class * loader (in order to be able to access the protected "defineClass" method) we would likely still * be able to load generated classes, however, they would not have access to package-private * classes and members of their super classes. * * @param className the full name of the class to be loaded * @param code the bytecode of the class to load * @param classLoader the class loader to use * @return the class instance */ public static Class<?> loadClass(String className, byte[] code, ClassLoader classLoader) { checkArgNotNull(className, "className"); checkArgNotNull(code, "code"); checkArgNotNull(classLoader, "classLoader"); try { Class<?> classLoaderBaseClass = Class.forName("java.lang.ClassLoader"); Method defineClassMethod = classLoaderBaseClass.getDeclaredMethod( "defineClass", String.class, byte[].class, int.class, int.class); // protected method invocation defineClassMethod.setAccessible(true); try { return (Class<?>) defineClassMethod.invoke(classLoader, className, code, 0, code.length); } finally { defineClassMethod.setAccessible(false); } } catch (Exception e) { throw new RuntimeException("Could not load class '" + className + '\'', e); } }