1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.beanutils.converters;
19
20 import java.io.InputStream;
21 import java.io.ByteArrayOutputStream;
22 import java.io.FileNotFoundException;
23 import java.io.IOException;
24
25 /***
26 * A special classloader useful for testing j2ee-like scenarios.
27 *
28 * <p>In some tests we want to be able to emulate "container" frameworks,
29 * where code runs in a hierarchy of classloaders, and certain classes may
30 * be loaded by various classloaders in the hierarchy.</p>
31 *
32 * <p>Normally this is done by having certain jars or class-file-directories
33 * in the classpath of some classloaders but not others. This is quite
34 * difficult difficult to integrate with the build process for the unit
35 * tests though; compiling certain classes and having the output go into
36 * places that is not in the default classpath for the unit tests would be
37 * a major pain.</p>
38 *
39 * <p>So this class takes a sneaky alternative approach: it can grab any class
40 * already loaded by a parent classloader and <i>reload</i> that class via this
41 * classloader. The effect is exactly as if a class (or jar file) had been
42 * present in the classpath for a container's "shared" classloader <i>and</i>
43 * been present in the component-specific classpath too, without any messing
44 * about with the way unit test code is compiled or executed.
45 */
46
47 public class ClassReloader extends ClassLoader {
48 public ClassReloader(ClassLoader parent) {
49 super(parent);
50 }
51
52 /***
53 * Given a class already in the classpath of a parent classloader,
54 * reload that class via this classloader.
55 */
56 public Class reload(Class clazz) throws FileNotFoundException, IOException {
57 String className = clazz.getName();
58 String classFile = className.replace('.', '/') + ".class";
59 InputStream classStream = getParent().getResourceAsStream(classFile);
60
61 if (classStream == null) {
62 throw new FileNotFoundException(classFile);
63 }
64
65 byte[] buf = new byte[1024];
66 ByteArrayOutputStream baos = new ByteArrayOutputStream();
67 for(;;) {
68 int bytesRead = classStream.read(buf);
69 if (bytesRead == -1)
70 break;
71 baos.write(buf, 0, bytesRead);
72 }
73 classStream.close();
74
75 byte[] classData = baos.toByteArray();
76
77
78 Class newClass = defineClass(className, classData, 0, classData.length);
79 resolveClass(newClass);
80 return newClass;
81 }
82 }