Få navne på klasser inde i en JAR-fil

1. Oversigt

De fleste Java-biblioteker er tilgængelige som JAR-filer. I denne vejledning beskæftiger vi os med, hvordan man får navne på klasser inde i en given JAR-fil fra kommandolinjen og fra et Java-program.

Derefter ser vi på et Java-programeksempel på indlæsning af klasser fra en given JAR-fil ved kørsel.

2. Eksempel på JAR-fil

I denne vejledning tager vi stripe-0.0.1-SNAPSHOT.jar fil som et eksempel for at adressere, hvordan man får klassenavne i JAR-filen:

3. Brug af krukke Kommando

JDK leveres med en krukke kommando. Vi kan bruge denne kommando med t og f indstillinger for at vise indholdet af en JAR-fil:

$ jar tf stripe-0.0.1-SNAPSHOT.jar META-INF / META-INF / MANIFEST.MF ... skabeloner / resultat.html skabeloner / 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 vi kun er interesseret i * .klasse filer i arkivet, kan vi filtrere output ved hjælp af grep kommando:

$ 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

Dette giver os en liste over klassefiler inde i JAR-filen.

4. Få klassenavne på en JAR-fil i Java

Bruger krukke kommandoen til at udskrive klassenavnene fra en JAR-fil er ret ligetil. Nogle gange vil vi dog indlæse nogle klasser fra en JAR-fil i vores Java-program. I dette tilfælde er kommandolinjens output ikke nok.

For at nå vores mål er vi nødt til det scanne JAR-filen fra et Java-program og få klassens navne.

Lad os se på, hvordan man udtrækker klassenavne fra vores eksempel på JAR-filen bruger JarFile og JarEntry klasser:

offentlig statisk sæt getClassNamesFromJarFile (File givenFile) kaster IOException {Set classNames = new HashSet (); prøv (JarFile jarFile = ny JarFile (givenFile)) {Enumeration e = jarFile.entries (); mens (e.hasMoreElements ()) {JarEntry jarEntry = e.nextElement (); hvis (jarEntry.getName (). endsWith (". class")) {String className = jarEntry.getName () .replace ("/", ".") .replace (". class", ""); classNames.add (className); }} returner classNames; }} 

Lad os nu se nærmere på koden i metoden ovenfor og forstå, hvordan den fungerer:

  • prøv (JarFile jarFile = ny JarFile (givenFile)) - Her brugte vi en prøve-med-ressourcer erklæring for at få jarFile fra det givne Fil objekt
  • hvis (jarEntry.getName (). endsWith (“. class”)) {…} - Vi tager hver klasse jarEntry, og rediger stien til klassefilen til det kvalificerede klassenavn, f.eks. ændring “Pakke1 / pakke2 / SomeType.class” ind i “Package1.package2.SomeType”

Lad os kontrollere, om metoden kan udtrække klassenavne fra vores eksempel JAR-fil gennem en enhedstestmetode:

privat statisk endelig String JAR_PATH = "eksempel-jar / stripe-0.0.1-SNAPSHOT.jar"; privat statisk endelig sæt 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 offentlig ugyldighed givenJarFilePath_whenLoadClassNames_thenGetClassNames () kaster IOException, URISyntaxException {File jarFile = ny fil (Objects.requireNonNull (getClass (). GetClassLoader (). GetResource (JAR_PATH)). Indstil classNames = GetClassNamesFromJar.getClassNamesFromJarFile (jarFile); Assert.assertEquals (EXPECTED_CLASS_NAMES, classNames); } 

5. Få klasser fra en JAR-fil i Java

Vi har set, hvordan man får klassens navne fra en JAR-fil. Nogle gange ønsker vi at indlæse nogle klasser fra en JAR-fil dynamisk ved runtime.

I dette tilfælde kan vi først hente klassens navne fra den givne JAR-fil ved hjælp af vores getClassNamesFromJarFile metode.

Dernæst kan vi oprette en ClassLoader at indlæse krævede klasser ved navn:

offentlig statisk sæt getClassesFromJarFile (File jarFile) kaster IOException, ClassNotFoundException {Set classNames = getClassNamesFromJarFile (jarFile); Indstil klasser = nyt HashSet (classNames.size ()); prøv (URLClassLoader cl = URLClassLoader.newInstance (ny URL [] {new URL ("jar: file:" + jarFile + "! /")})) {for (String name: classNames) {Class clazz = cl.loadClass ( navn); // Indlæs klassen efter dens navne classes.add (clazz); }} returnere klasser; }

I ovenstående metode oprettede vi en URLClassLoader modstand mod at indlæse klasserne. Implementeringen er ret ligetil.

Det er dog sandsynligvis værd at forklare syntaksen for JAR URL en smule. En gyldig JAR-URL indeholder tre dele: “krukke: + [placeringen af ​​JAR-filen] + !/”.

Den afsluttende “!/”Angiver, at JAR-URL'en henviser til en hel JAR-fil. Lad os se et par eksempler på JAR URL:

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

I vores getClassesFromJarFile metode, er JAR-filen placeret på det lokale filsystem, og derfor er URL-præfikset “fil:“.

Lad os nu skrive en testmetode for at kontrollere, om vores metode kan få alle forventede Klasse genstande:

@Test offentlig ugyldighed givenJarFilePath_whenLoadClass_thenGetClassObjects () kaster IOException, ClassNotFoundException, URISyntaxException {File jarFile = ny fil (Objects.requireNonNull (getClass (). GetClassLoader (). GetResAT) Indstil klasser = GetClassNamesFromJar.getClassesFromJarFile (jarFile); Indstil navne = classes.stream (). Map (Class :: getName) .collect (Collectors.toSet ()); Assert.assertEquals (EXPECTED_CLASS_NAMES, navne); } 

Når vi har det nødvendige Klasse objekter, kan vi bruge Java-refleksion til at oprette forekomster af klasser og påberåbe sig metoder.

6. Konklusion

I denne artikel har vi lært to forskellige tilgange til at få klassenavne fra en given JAR-fil.

Det krukke kommando kan udskrive klassens navne. Det er ret praktisk, hvis vi skal kontrollere, om en JAR-fil indeholder en given klasse. Men hvis vi har brug for at få klassenavnene fra et kørende Java-program, JarFile og JarEntry kan hjælpe os med at opnå det.

Endelig har vi også set et eksempel på et Java-program til at indlæse klasser fra en JAR-fil ved kørsel.

Som altid er artiklens fulde kildekode tilgængelig på GitHub.