This blog has moved to Medium

Subscribe via email


WarClassLoader – load your classes straight from a war

I was of need of a Java Class Loader that can load classes from within a war file.
It took me a bit to find this – in fact, I found it when I looked for ZipClassLoader (a war file is a zip with a specific folder structure). I found this post, and modified it to take the war folder structure into account:

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
 
/**
 * Loads classes from war files. See http://www2.java.net/blog/2008/07/25/how-load-classes-jar-or-zip
 */
public final class WarClassLoader extends ClassLoader {
    private final ZipFile file;
 
    public WarClassLoader(String filename) throws IOException {
        this.file = new ZipFile(filename);
    }
 
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        ZipEntry entry = this.file.getEntry("WEB-INF/classes/" + name.replace('.', '/') + ".class");
        if (entry == null) {
            throw new ClassNotFoundException(name);
        }
        try {
            byte[] array = new byte[1024];
            InputStream in = this.file.getInputStream(entry);
            ByteArrayOutputStream out = new ByteArrayOutputStream(array.length);
            int length = in.read(array);
            while (length > 0) {
                out.write(array, 0, length);
                length = in.read(array);
            }
            return defineClass(name, out.toByteArray(), 0, out.size());
        }
        catch (IOException exception) {
            throw new ClassNotFoundException(name, exception);
        }
    }
}

Two notes:

  1. This code isn’t really production grade, as the streams aren’t closed and whatnot
  2. It is missing one critical addition – if the classes in the war depend on the jars that are included within it, this class loader will not be able to load these classes. I managed to work around the problem because I already had all those jars in my classpath anyway, but in principle the code above needs a bit of extension to be able to work with the embedded jars.