Klassen aus einer inneren Jar-Datei (Jar in Jar) laden

Fabio Hellmann

Erfahrenes Mitglied
Hi zusammen,
ich versuche zur Zeit einen ClassLoader zu schreiben, der Klassen aus einer Jar-Datei laden kann, die innerhalb einer Jar-Datei liegt.
Die Struktur einer solchen Jar-Datei kann wie folgt aussehen:
Code:
+ Jar
  # package/package/package
  # package/package
  # package/package/package/package
  # META-INF/
  # Jar1
  # Jar2
  # Jar3
Bei meinem Beispiel, stellen die Dateien Jar1-3 eine Library (z.B. commons-io, etc.) dar. Diese Libaray - oder nur eine bestimmte Klasse daraus - will ich nun in die Laufzeitumgebung laden. Das ist schwieriger als es vielleicht klingt.

Ich hab mir erstmal ein JUnit-Test dafür angelegt:
Java:
public class JarClassLoaderTest extends TestCase
{
	private static final File jarFile = new File("./Tests/Test.jar");
	private final URL jarFileUrl;
	private final JarURLConnection con;
	
	/**
	 * @throws Exception 
	 */
	public JarClassLoaderTest() throws Exception {
		jarFileUrl = new URL("jar:file:" + jarFile.getAbsolutePath() + "!/");
		con = (JarURLConnection) jarFileUrl.openConnection();
		con.connect();
		System.out.println("Connected to JarFile="+jarFileUrl.getPath());
	}

	/** @throws Exception */
	public void testLoadJars() throws Exception {
		final URLJarFile j = (URLJarFile) con.getContent();
		System.out.println(j.getName());
		final List<JarEntry> jarFiles = filterJarFiles(j.entries());
		for(final JarEntry jarEntry : jarFiles) {
			System.out.println(jarEntry.getName());
			if(jarEntry.getName().startsWith("commons-io")) {
				final URL innerJarFileUrl = new URL("jar:"+jarFileUrl.getPath()+jarEntry.getName());
				System.out.println(innerJarFileUrl);
				final ClassLoader cl = new URLClassLoader(new URL[] {innerJarFileUrl}, this.getClass().getClassLoader());
			
				final Class<?> loadClass = Class.forName("org.apache.commons.io.IOUtils", true, cl);
			}
		}
	}
	
	/**
	 * @param entries
	 * @return
	 */
	private List<JarEntry> filterJarFiles(final Enumeration<JarEntry> entries) {
		final List<JarEntry> jarList = new ArrayList<JarEntry>();
		while(entries.hasMoreElements()) {
			final JarEntry je = entries.nextElement();
			final String name = je.getName();
			if(name.endsWith(".jar")) {
				jarList.add(je);
			}
		}
		return jarList;
	}
}
Vielleicht hat jemand von euch ja einen genialen Einfall dazu. Würde mich freuen. :)

ps.: Um zu überprüfen, dass die Klasse/Jar nicht schon vorher geladen wurde, habe ich der VM folgenden Parameter '-verbose:class' übergeben. Dadurch bekommt man alle geladenen/geöffneten Klassen/Jars angezeigt.

Gruß

Fabio
 
Sollte der Standard-Classloader nicht genau das können, was du möchtest? Eclipse packt ja auch auf Wunsch Jar-Archive in die generierten Jar-Archive.
 
Das sollte man eigentlich meinen, dass der das kann.

Das oberste Jar ist bei mir ein Executable-Jar. Wenn ich das aufrufe, dann will ich mithilfe des ClassLoaders Klassen aus den inneren Jars laden. So zumindest mein Plan.

// EDIT:
Da es mir gerade eben aufgefallen ist. Die "inneren" Jar-Dateien liegen auch im Class-Path der Jar. Gibt es nicht eine Möglichkeit, evtl. sogar einfach nur die Jars - die im Class-Path liegen - auf die "inneren" Jar-Dateien zeigen zu lassen. Sodass ich mich gar nicht um den ClassLoader etc. kümmern muss?
 
Zuletzt bearbeitet:
Zurück