Abrufen von Klassennamen in einer JAR-Datei

1. Übersicht

Die meisten Java-Bibliotheken sind als JAR-Dateien verfügbar. In diesem Tutorial erfahren Sie, wie Sie Klassennamen in einer bestimmten JAR-Datei über die Befehlszeile und über ein Java-Programm abrufen.

Anschließend sehen wir uns ein Java-Programmbeispiel zum Laden der Klassen aus einer bestimmten JAR-Datei zur Laufzeit an.

2. Beispiel-JAR-Datei

In diesem Tutorial nehmen wir die Datei stripe-0.0.1-SNAPSHOT.jar als Beispiel, um zu erfahren , wie die Klassennamen in der JAR-Datei abgerufen werden:

3. Verwenden Sie den Befehl jar

JDK wird mit einem JAR- Befehl ausgeliefert. Wir können diesen Befehl mit den Optionen t und f verwenden , um den Inhalt einer JAR-Datei aufzulisten :

$ jar tf stripe-0.0.1-SNAPSHOT.jar META-INF/ META-INF/MANIFEST.MF ... templates/result.html templates/checkout.html application.properties com/baeldung/stripe/StripeApplication.class com/baeldung/stripe/ChargeRequest.class com/baeldung/stripe/StripeService.class com/baeldung/stripe/ChargeRequest$Currency.class ...

Da wir nur an den * .class- Dateien im Archiv interessiert sind , können wir die Ausgabe mit dem Befehl grep filtern :

$ jar tf stripe-0.0.1-SNAPSHOT.jar | grep '\.class$' com/baeldung/stripe/StripeApplication.class com/baeldung/stripe/ChargeRequest.class com/baeldung/stripe/StripeService.class com/baeldung/stripe/ChargeRequest$Currency.class com/baeldung/stripe/ChargeController.class com/baeldung/stripe/CheckoutController.class

Dies gibt uns eine Liste von Klassendateien in der JAR-Datei.

4. Abrufen von Klassennamen einer JAR-Datei in Java

Die Verwendung des Befehls jar zum Drucken der Klassennamen aus einer JAR-Datei ist ziemlich einfach. Manchmal möchten wir jedoch einige Klassen aus einer JAR-Datei in unser Java-Programm laden. In diesem Fall reicht die Befehlszeilenausgabe nicht aus.

Um unser Ziel zu erreichen, müssen wir die JAR-Datei aus einem Java-Programm scannen und die Klassennamen abrufen.

Lassen Sie uns einen Blick darauf werfen, wie Klassennamen aus unserer Beispiel-JAR-Datei mithilfe der Klassen JarFile und JarEntry extrahiert werden :

public static Set getClassNamesFromJarFile(File givenFile) throws IOException { Set classNames = new HashSet(); try (JarFile jarFile = new JarFile(givenFile)) { Enumeration e = jarFile.entries(); while (e.hasMoreElements()) { JarEntry jarEntry = e.nextElement(); if (jarEntry.getName().endsWith(".class")) { String className = jarEntry.getName() .replace("/", ".") .replace(".class", ""); classNames.add(className); } } return classNames; } } 

Schauen wir uns nun den Code in der obigen Methode genauer an und verstehen, wie er funktioniert:

  • try (JarFile jarFile = new JarFile (GivenFile)) - Hier haben wir eine try-with-resources-Anweisung verwendet, um die jarFile aus dem angegebenen File- Objekt abzurufen
  • if (jarEntry.getName (). endetWith (". class")) {…} - Wir nehmen jede Klasse jarEntry und ändern den Pfad der Klassendatei in den qualifizierten Klassennamen, zum Beispiel "package1 / package2 / SomeType". Klasse “ in “ package1.package2.SomeType ”

Lassen Sie uns überprüfen, ob die Methode die Klassennamen aus unserer Beispiel-JAR-Datei mithilfe einer Unit-Test-Methode extrahieren kann:

private static final String JAR_PATH = "example-jar/stripe-0.0.1-SNAPSHOT.jar"; private static final Set EXPECTED_CLASS_NAMES = Sets.newHashSet( "com.baeldung.stripe.StripeApplication", "com.baeldung.stripe.ChargeRequest", "com.baeldung.stripe.StripeService", "com.baeldung.stripe.ChargeRequest$Currency", "com.baeldung.stripe.ChargeController", "com.baeldung.stripe.CheckoutController"); @Test public void givenJarFilePath_whenLoadClassNames_thenGetClassNames() throws IOException, URISyntaxException { File jarFile = new File( Objects.requireNonNull(getClass().getClassLoader().getResource(JAR_PATH)).toURI()); Set classNames = GetClassNamesFromJar.getClassNamesFromJarFile(jarFile); Assert.assertEquals(EXPECTED_CLASS_NAMES, classNames); } 

5. Abrufen von Klassen aus einer JAR-Datei in Java

Wir haben gesehen, wie die Klassennamen aus einer JAR-Datei abgerufen werden. Manchmal möchten wir einige Klassen zur Laufzeit dynamisch aus einer JAR-Datei laden.

In diesem Fall können wir zuerst die Klassennamen aus der angegebenen JAR-Datei mit unserer Methode getClassNamesFromJarFile abrufen .

Als Nächstes können wir einen ClassLoader erstellen , um die erforderlichen Klassen nach Namen zu laden:

public static Set getClassesFromJarFile(File jarFile) throws IOException, ClassNotFoundException { Set classNames = getClassNamesFromJarFile(jarFile); Set classes = new HashSet(classNames.size()); try (URLClassLoader cl = URLClassLoader.newInstance( new URL[] { new URL("jar:file:" + jarFile + "!/") })) { for (String name : classNames) { Class clazz = cl.loadClass(name); // Load the class by its name classes.add(clazz); } } return classes; }

In der obigen Methode haben wir ein URLClassLoader- Objekt erstellt, um die Klassen zu laden. Die Implementierung ist ziemlich einfach.

Es lohnt sich jedoch wahrscheinlich, die Syntax für die JAR-URL ein wenig zu erläutern. Eine gültige JAR-URL besteht aus drei Teilen: " jar: + [der Speicherort der JAR-Datei] + ! /".

Das abschließende " ! / " Zeigt an, dass sich die JAR-URL auf eine gesamte JAR-Datei bezieht. Sehen wir uns einige Beispiele für JAR-URLs an:

jar://www.example.com/some_jar_file.jar!/ jar:file:/local/path/to/some_jar_file.jar!/ jar:file:/C:/windows/path/to/some_jar_file.jar!/

In unserer Methode getClassesFromJarFile befindet sich die JAR-Datei im lokalen Dateisystem. Daher lautet das Präfix der URL „ file: “.

Schreiben wir nun eine Testmethode, um zu überprüfen, ob unsere Methode alle erwarteten Klassenobjekte abrufen kann:

@Test public void givenJarFilePath_whenLoadClass_thenGetClassObjects() throws IOException, ClassNotFoundException, URISyntaxException { File jarFile = new File(Objects.requireNonNull(getClass().getClassLoader().getResource(JAR_PATH)).toURI()); Set classes = GetClassNamesFromJar.getClassesFromJarFile(jarFile); Set names = classes.stream().map(Class::getName).collect(Collectors.toSet()); Assert.assertEquals(EXPECTED_CLASS_NAMES, names); } 

Nachdem wir die erforderlichen haben Class - Objekte, können wir Java Reflexion verwenden Instanzen von Klassen zu erstellen und Methoden aufrufen.

6. Fazit

In diesem Artikel haben wir zwei verschiedene Ansätze zum Abrufen von Klassennamen aus einer bestimmten JAR-Datei kennengelernt.

Der Befehl jar kann die Klassennamen drucken. Es ist ziemlich praktisch, wenn wir überprüfen müssen, ob eine JAR-Datei eine bestimmte Klasse enthält. Wenn wir jedoch die Klassennamen von einem laufenden Java-Programm erhalten müssen, können JarFile und JarEntry uns dabei helfen.

Endlich haben wir auch ein Beispiel für ein Java-Programm zum Laden von Klassen aus einer JAR-Datei zur Laufzeit gesehen.

Wie immer ist der vollständige Quellcode des Artikels auf GitHub verfügbar.