カレントスレッドのクラスローダに定義するように修正。すこしはマシかな…
package jarjar;import java.io.*;
import java.lang.reflect.*;
import java.util.*;
import java.util.jar.*;public class JarJar {
public static void main(String args) {
try {
ClassLoader cloader = Thread.currentThread().getContextClassLoader();
JarJar jarjar = new JarJar("ooweb-0.5.jar", cloader);
jarjar.load();
println(Class.forName("net.sf.ooweb.util.StringUtils"));
} catch (Throwable e) {
e.printStackTrace();
}
}private static void println(Object x) {
System.out.println(x);
}/////////////////////////////////////////////////////////////////
private JarFile jar = null;private ClassLoader cloader = null;
private Method define = null;
private static final Integer ZERO = new Integer(0);
public JarJar(String filename, ClassLoader cloader) throws IOException {
this.jar = new JarFile(filename);
this.cloader = cloader;
Class args = { String.class, byte.class, int.class, int.class };try {
define = ClassLoader.class.getDeclaredMethod("defineClass", args);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}define.setAccessible(true);
}public void load() throws IOException {
Map ctx = new HashMap();for (Enumeration enum = jar.entries(); enum.hasMoreElements();) {
JarEntry entry = (JarEntry) enum.nextElement();
String name = entry.getName();if (entry.isDirectory() || !name.endsWith(".class"))
continue;byte bs = getBytes(jar, entry);
ctx.put(getClassName(name), bs);
}Set classes = new HashSet();
for (Iterator names = ctx.keySet().iterator(); names.hasNext();) {
String name = (String) names.next();
loadClasses(name, ctx, classes);
}
}private void loadClasses(String name, Map ctx, Set classes) {
if (classes.contains(name))
return;byte bs = (byte) ctx.get(name);
try {
defineClass(name, bs);
} catch (NoClassDefFoundError e) {
loadClasses(getClassName(e.getMessage()), ctx, classes);
defineClass(name, bs);
}classes.add(name);
}private byte getBytes(JarFile jar, JarEntry entry) throws IOException {
InputStream in = jar.getInputStream(entry);
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte buf = new byte[1024];while (in.available() > 0) {
int len = in.read(buf);
out.write(buf, 0, len);
}out.flush();
in.close();
return out.toByteArray();
}private String getClassName(String name) {
name = name.replace('/', '.');if (name.endsWith(".class"))
name = name.substring(0, name.length() - 6);return name;
}private void defineClass(String name, byte bs) {
try {
if (define == null) {
}Object objs = { name, bs, ZERO, new Integer(bs.length) };
define.invoke(cloader, objs);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
Throwable cause = e.getCause();if (cause instanceof NoClassDefFoundError)
throw (NoClassDefFoundError) cause;throw new RuntimeException(e);
}
}}