I have made a little utility which wraps a given JAR file in a Bzip2 compression wrapper giving smaller JAR file sizes while keeping the same functionality.
It can be downloaded here: http://www.geocities.com/budgetanime/bJAR.html
It currently performs as excpected with Executable JARs. It does not work with normal Library JARs. In order to make library JARs work I need to be able to add resources to the class path from a static method. My current code which adds resources to the class path only works from the main thread. i.e. from the public static void main (String args[]) method or any called methods.
The code which adds the compressed JAR to the class path:
import java.io.*;
import java.lang.reflect.*;
import java.net.*;
public class bJARLoader
{
static private bJARLoader instance;
static
{
instance=new bJARLoader();
// URL dataURL=instance.getClass().getResource("data.bz2");
// URL.setURLStreamHandlerFactory(new ExtendedStreamHandlerFactory(dataURL));
//
// try
// {
// addURL(new URL("bjar:data.jar"));
// }
// catch (IOException e)
// {
// e.printStackTrace();
// System.exit(1);
// }
}
static final int BUFFER = 2048;
public static void main(String[] args) throws Exception
{
URL infoURL=instance.getClass().getResource("bJAR.info");
URL dataURL=instance.getClass().getResource("data.bz2");
URL.setURLStreamHandlerFactory(new ExtendedStreamHandlerFactory(dataURL));
addURL(new URL("bjar:data.jar"));
BufferedReader br = new BufferedReader(new InputStreamReader(infoURL.openStream()));
String startClassName = br.readLine();
if (startClassName!=null)
{
startClassName=startClassName.substring("Main-Class: ".length());
runActualJar(startClassName,args);
}
}
// The methods addFile and associated final Class[] parameters were
// gratefully copied from
// anthony_miguel @ http://forum.java.sun.com/thread.jsp?forum=32&thread=300557&tstart=0&trange=15
private static final Class[] parameters = new Class[]{URL.class};
public static void addFile(String s) throws IOException {
File f = new File(s);
addFile(f);
}//end method
public static void addFile(File f) throws IOException {
addURL(f.toURL());
}//end method
public static void addURL(URL u) throws IOException {
URLClassLoader sysloader = (URLClassLoader) ClassLoader.getSystemClassLoader();
Class sysclass = URLClassLoader.class;
try {
Method method = sysclass.getDeclaredMethod("addURL",parameters);
method.setAccessible(true);
method.invoke(sysloader,new Object[]{ u });
} catch (Throwable t) {
t.printStackTrace();
throw new IOException("Error, could not add URL to system classloader");
}//end try catch
}//end method
// runs the main method of the compressed JAR
private static void runActualJar(String startClassName, String[] variables) throws Exception
{
Class startClass = Class.forName(startClassName);
Class[] sig = new Class[1];
sig[0] = String[].class;
Object[] param = new Object[1];
param[0] = variables;
Method bb = startClass.getMethod("main", sig);
Object cc = bb.invoke(null, param);
}
}
The actual adding occurs in the AddURL() method.
When i de-comment the block of code in the static block at the top of the listing hoping to add the JAR contents to the class path before instaniation, there is an exception indicating that the addURL() method for the system class loader does not exisit. This method does seem to exist when called from the main method.
My question is how can i add resources to the main system class loader from a static block of code…