Ottieni nomi di classi all'interno di un file JAR

1. Panoramica

La maggior parte delle librerie Java sono disponibili come file JAR. In questo tutorial, spiegheremo come ottenere i nomi delle classi all'interno di un determinato file JAR dalla riga di comando e da un programma Java.

Quindi, esamineremo un esempio di programma Java di caricamento delle classi da un determinato file JAR in fase di esecuzione.

2. File JAR di esempio

In questo tutorial, prenderemo il file stripe-0.0.1-SNAPSHOT.jar come esempio per affrontare come ottenere i nomi delle classi nel file JAR:

3. Utilizzo del comando jar

JDK viene fornito con un comando jar . Possiamo usare questo comando con le opzioni t e f per elencare il contenuto di un file JAR :

$ 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 ...

Dato che siamo interessati solo ai file * .class nell'archivio, possiamo filtrare l'output usando il comando grep :

$ 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

Questo ci dà un elenco di file di classe all'interno del file JAR.

4. Ottenere i nomi delle classi di un file JAR in Java

Usare il comando jar per stampare i nomi delle classi da un file JAR è piuttosto semplice. Tuttavia, a volte vogliamo caricare alcune classi da un file JAR nel nostro programma Java. In questo caso, l'output della riga di comando non è sufficiente.

Per raggiungere il nostro obiettivo, dobbiamo eseguire la scansione del file JAR da un programma Java e ottenere i nomi delle classi.

Diamo un'occhiata a come estrarre i nomi delle classi dal nostro file JAR di esempio utilizzando le classi JarFile e JarEntry :

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; } } 

Ora, diamo un'occhiata più da vicino al codice nel metodo sopra e capiamo come funziona:

  • provare (JarFile JarFile = nuovo JarFile (givenFile)) - Qui, abbiamo usato un'istruzione try-con-le risorse per ottenere il JarFile dal dato file oggetto
  • if (jarEntry.getName () .endsWith (". class")) {…} - Prendiamo ogni classe jarEntry e cambiamo il percorso del file di classe nel nome della classe qualificato, ad esempio cambia "pacchetto1 / pacchetto2 / SomeType. class " in " package1.package2.SomeType "

Verifichiamo se il metodo può estrarre i nomi delle classi dal nostro file JAR di esempio tramite un metodo di unit test:

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. Ottenere classi da un file JAR in Java

Abbiamo visto come ottenere i nomi delle classi da un file JAR. A volte, vogliamo caricare dinamicamente alcune classi da un file JAR in fase di esecuzione.

In questo caso, possiamo prima ottenere i nomi delle classi dal file JAR specificato utilizzando il nostro metodo getClassNamesFromJarFile .

Successivamente, possiamo creare un ClassLoader per caricare le classi richieste per nome:

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; }

Nel metodo sopra, abbiamo creato un oggetto URLClassLoader per caricare le classi. L'implementazione è piuttosto semplice.

Tuttavia, probabilmente vale la pena spiegare un po 'la sintassi per l'URL JAR. Un URL JAR valido contiene tre parti: " jar: + [la posizione del file JAR] + ! /".

La terminazione " ! / " Indica che l'URL JAR fa riferimento a un intero file JAR. Vediamo alcuni esempi di URL JAR:

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!/

Nel nostro metodo getClassesFromJarFile , il file JAR si trova sul filesystem locale, quindi il prefisso dell'URL è " file: ".

Ora, scriviamo un metodo di test per verificare se il nostro metodo può ottenere tutti gli oggetti Class previsti :

@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); } 

Una volta che abbiamo gli oggetti Class richiesti , possiamo usare la riflessione Java per creare istanze di classi e invocare metodi.

6. Conclusione

In questo articolo, abbiamo imparato due diversi approcci per ottenere i nomi delle classi da un determinato file JAR.

Il comando jar può stampare i nomi delle classi. È molto utile se dobbiamo controllare se un file JAR contiene una data classe. Tuttavia, se dobbiamo ottenere i nomi delle classi da un programma Java in esecuzione, JarFile e JarEntry possono aiutarci a raggiungere questo obiettivo.

Infine, abbiamo anche visto un esempio di un programma Java per caricare classi da un file JAR in fase di runtime.

Come sempre, il codice sorgente completo dell'articolo è disponibile su GitHub.