วิธีรับชื่อคลาสภายในไฟล์ jar


112

ฉันมีไฟล์ JAR และฉันต้องการชื่อคลาสทั้งหมดในไฟล์ JAR นี้ ฉันจะทำเช่นนั้นได้อย่างไร?

ฉัน googled และเห็นบางอย่างเกี่ยวกับ JarFile หรือ Java ClassLoaderแต่ฉันไม่รู้ว่าจะทำอย่างไร


คุณใช้ IDE อยู่หรือไม่เนื่องจากจะแสดงอัตโนมัติหากคุณใช้งาน
joey rohan

ฉันใช้ Eclipse แต่ฉันต้องใช้รหัส
sticksu

@LuiggiMendoza - สิ่งที่อาจเกิดขึ้นซ้ำมีคำตอบพร้อมตัวอย่างและแหล่งข้อมูลสำหรับเอกสารประกอบ การค้นหาชื่อคลาส + ตัวอย่างจะให้ผลลัพธ์ที่เป็นประโยชน์หลายประการ
Aiias

@Alias ​​การทำซ้ำที่เป็นไปได้ระบุวิธีค้นหาและรับไฟล์จาก jar ในขณะที่คำถามเกี่ยวกับการรับชื่อคลาสภายใน jar (อาจเป็นคลาสในแพ็คเกจทั้งหมดที่อยู่ในนั้น) ลิงก์ในคำตอบของ ErikKaju ชี้ไปที่วิธีแก้ปัญหาที่เป็นไปได้โดยใช้JarInputStreamและJarEntryชั้นเรียนที่ฉันไม่พบคำตอบใด ๆ ของลิงก์ที่คุณอ้างถึง
Luiggi Mendoza

คำตอบ:


68

น่าเสียดายที่ Java ไม่มีวิธีง่ายๆในการแสดงรายการคลาสใน JRE "เนทีฟ" ซึ่งทำให้คุณมีสองตัวเลือก: (a) สำหรับไฟล์ JAR ใด ๆ ที่กำหนดคุณสามารถแสดงรายการภายในไฟล์ JAR นั้นค้นหา.classไฟล์จากนั้นกำหนดคลาส Java ที่แต่ละ.classไฟล์แทน หรือ (b) คุณสามารถใช้ไลบรารีที่ทำเพื่อคุณ

ตัวเลือก (a): การสแกนไฟล์ JAR ด้วยตนเอง

ในตัวเลือกนี้เราจะเติมเต็มclassNamesกับรายชื่อของทุกชั้นเรียน Java ที่มีอยู่ภายใน jar /path/to/jar/file.jarไฟล์ที่

List<String> classNames = new ArrayList<String>();
ZipInputStream zip = new ZipInputStream(new FileInputStream("/path/to/jar/file.jar"));
for (ZipEntry entry = zip.getNextEntry(); entry != null; entry = zip.getNextEntry()) {
    if (!entry.isDirectory() && entry.getName().endsWith(".class")) {
        // This ZipEntry represents a class. Now, what class does it represent?
        String className = entry.getName().replace('/', '.'); // including ".class"
        classNames.add(className.substring(0, className.length() - ".class".length()));
    }
}

ตัวเลือก (b): การใช้ไลบรารีสะท้อนพิเศษ

ฝรั่ง

ฝรั่งก็เคยมีClassPathตั้งแต่อย่างน้อย 14.0 ซึ่งฉันเคยใช้และชอบ สิ่งที่ดีอย่างหนึ่งClassPathคือมันไม่โหลดคลาสที่พบซึ่งเป็นสิ่งสำคัญเมื่อคุณกำลังสแกนหาคลาสจำนวนมาก

ClassPath cp=ClassPath.from(Thread.currentThread().getContextClassLoader());
for(ClassPath.ClassInfo info : cp.getTopLevelClassesRecurusive("my.package.name")) {
    // Do stuff with classes here...
}

สะท้อน

ฉันไม่ได้ใช้ไลบรารี Reflectionsเป็นการส่วนตัวแต่ดูเหมือนว่าจะชอบ บางตัวอย่างที่ดีมีไว้ในเว็บไซต์เช่นนี้วิธีที่รวดเร็วในการโหลดทุกชั้นเรียนในแพคเกจที่ให้บริการโดยใด ๆ JAR ไฟล์ซึ่งอาจจะเป็นประโยชน์สำหรับการใช้งานของคุณ

Reflections reflections = new Reflections("my.project.prefix");

Set<Class<? extends SomeType>> subTypes = reflections.getSubTypesOf(SomeType.class);

Set<Class<?>> annotated = reflections.getTypesAnnotatedWith(SomeAnnotation.class);

การสะท้อนจะไม่ทำงานหากเรียกใช้จาก jar ที่เรียกใช้งานได้
ลุค

วิธีการแก้ปัญหาการทำงานจากฤดูใบไม้ผลิขวดปฏิบัติการ: stackoverflow.com/a/21430849/4265610
ลุค

1
เพียงแค่ใช้. โถ tvf jarfile.jar. ทำไมคุณถึงทำทั้งหมดนี้เพื่อ.
Philip Rego

185

คุณสามารถใช้jarเครื่องมือJava แสดงรายการเนื้อหาของไฟล์ jar ในไฟล์ txt และคุณสามารถดูคลาสทั้งหมดใน jar

jar tvf jarfile.jar

-t แสดงรายการสารบัญสำหรับเก็บถาวร

-v สร้างเอาต์พุต verbose บนเอาต์พุตมาตรฐาน

-f ระบุชื่อไฟล์เก็บถาวร


1
ขอบคุณ. คำตอบนี้ตอบโจทย์ส่วน "รับรายชื่อชั้นเรียน" ของ OP ที่ไม่ได้ถาม
octopusgrabbus

9
คุณยังสามารถใช้unzip -l jarfile.jarในการหยิก ไฟล์ JAR เป็นเพียงไฟล์ zip ที่มีรายการ!
sigpwned

3
ปัญหาคือเขาน่าจะต้องการรับไฟล์คลาสภายใน jar ที่รันไทม์โดยให้อินสแตนซ์ classloader (น่าจะดูว่ามีคลาสใดบ้างที่โหลดภายใน jar นั้น ๆ )
Richard Duerr

19

บางทีคุณอาจกำลังมองหาjarคำสั่งเพื่อรับรายชื่อคลาสในเทอร์มินัล

$ jar tf ~/.m2/repository/org/apache/spark/spark-assembly/1.2.0-SNAPSHOT/spark-assembly-1.2.0-SNAPSHOT-hadoop1.0.4.jar 
META-INF/
META-INF/MANIFEST.MF
org/
org/apache/
org/apache/spark/
org/apache/spark/unused/
org/apache/spark/unused/UnusedStubClass.class
META-INF/maven/
META-INF/maven/org.spark-project.spark/
META-INF/maven/org.spark-project.spark/unused/
META-INF/maven/org.spark-project.spark/unused/pom.xml
META-INF/maven/org.spark-project.spark/unused/pom.properties
META-INF/NOTICE

ที่ไหน

-t  list table of contents for archive
-f  specify archive file name

หรือเพียงแค่ grep ด้านบนผลลัพธ์เพื่อดู.classes เท่านั้น

$ jar tf ~/.m2/repository/org/apache/spark/spark-assembly/1.2.0-SNAPSHOT/spark-assembly-1.2.0-SNAPSHOT-hadoop1.0.4.jar | grep .class
org/apache/spark/unused/UnusedStubClass.class

หากต้องการดูจำนวนclasses

jar tvf launcher/target/usergrid-launcher-1.0-SNAPSHOT.jar | grep .class | wc -l
61079

2
นี่คือสิ่งที่ฉันต้องการแม้ว่าเจ้าของคำถามจะต้องการโซลูชันที่ใช้รหัสก็ตาม ขอบคุณ!
Providencemac

10

นี่คือแฮ็คที่ฉันใช้:

คุณสามารถใช้การjavaเติมข้อความอัตโนมัติได้ดังนี้:

java -cp path_to.jar <Tab>

สิ่งนี้จะให้รายชื่อชั้นเรียนที่สามารถผ่านเป็นคลาสเริ่มต้นได้ แน่นอนว่าการพยายามใช้ไฟล์ที่ไม่มีไฟล์หลักจะไม่ทำอะไรเลย แต่คุณจะเห็นjavaว่าคลาสที่อยู่ใน.jarนั้นเรียกว่าอะไร



6

คุณสามารถลอง:

jar tvf jarfile.jar 

สิ่งนี้จะเป็นประโยชน์ก็ต่อเมื่อ jar ของคุณสามารถเรียกใช้งานได้เช่นใน manifest คุณได้กำหนดคลาสบางคลาสเป็นคลาสหลัก


เพิ่มตัวอย่างที่เฉพาะเจาะจงในโถตัวอย่างในคำตอบของคุณ
Juru

4

คำสั่งด้านล่างนี้จะแสดงรายการเนื้อหาของไฟล์ jar

คำสั่ง: - unzip -l jarfilename.jar.

ตัวอย่าง o / p: -

Archive: hello-world.jar Length Date Time Name --------- ---------- ----- ---- 43161 10-18-2017 15:44 hello-world/com/ami/so/search/So.class 20531 10-18-2017 15:44 hello-world/com/ami/so/util/SoUtil.class --------- ------- 63692 2 files

ตามคู่มือของ unzip

-l แสดงรายการไฟล์เก็บถาวร (รูปแบบสั้น) ชื่อขนาดไฟล์ที่ไม่บีบอัดและวันที่แก้ไขและเวลาของไฟล์ที่ระบุจะถูกพิมพ์พร้อมกับผลรวมสำหรับไฟล์ทั้งหมดที่ระบุ ถ้า UnZip ถูกคอมไพล์โดยใช้ OS2_EAS ที่กำหนดไว้ตัวเลือก -l จะแสดงคอลัมน์สำหรับขนาดของแอ็ตทริบิวต์ส่วนขยาย OS / 2 (EAs) ที่เก็บไว้และรายการควบคุมการเข้าถึง OS / 2 (ACL) นอกจากนี้ความคิดเห็น zipfile และความคิดเห็นของแต่ละไฟล์ (ถ้ามี) จะปรากฏขึ้น หากไฟล์ถูกเก็บถาวรจากระบบไฟล์เคสเดียว (ตัวอย่างเช่นระบบไฟล์ MS-DOS FAT เก่า) และอ็อพชัน -L ถูกกำหนดชื่อไฟล์จะถูกแปลงเป็นตัวพิมพ์เล็กและขึ้นต้นด้วยเครื่องหมายคาเร็ต (^)


ขณะที่ข้อมูลโค้ดนี้คือการต้อนรับและอาจให้ความช่วยเหลือบางส่วนก็จะได้รับการปรับปรุงอย่างมากถ้ามันรวมถึงคำอธิบายของวิธีการและเหตุผลที่แก้ปัญหานี้ จำไว้ว่าคุณกำลังตอบคำถามสำหรับผู้อ่านในอนาคตไม่ใช่แค่คนที่ถามตอนนี้! โปรดแก้ไขคำตอบของคุณเพื่อเพิ่มคำอธิบายและระบุข้อ จำกัด และสมมติฐานที่ใช้
Toby Speight

2

คุณสามารถลองสิ่งนี้:

unzip -v /your/jar.jar

สิ่งนี้จะเป็นประโยชน์ก็ต่อเมื่อ jar ของคุณสามารถเรียกใช้งานได้เช่นใน manifest คุณได้กำหนดคลาสบางคลาสเป็นคลาสหลัก


1

ใช้สคริปต์ทุบตีนี้:

#!/bin/bash

for VARIABLE in *.jar
do
   jar -tf $VARIABLE |grep "\.class"|awk -v arch=$VARIABLE '{print arch ":" $4}'|sed 's/\//./g'|sed 's/\.\.//g'|sed 's/\.class//g'
done

สิ่งนี้จะแสดงรายการคลาสภายในขวดในไดเร็กทอรีของคุณในรูปแบบ:

file1.jar:fullyqualifiedclassName
file1.jar:fullyqualifiedclassName
file1.jar:fullyqualifiedclassName
file1.jar:fullyqualifiedclassName
file2.jar:fullyqualifiedclassName
file2.jar:fullyqualifiedclassName
file2.jar:fullyqualifiedclassName

ตัวอย่างผลลัพธ์:

commons-io.jar:org.apache.commons.io.ByteOrderMark
commons-io.jar:org.apache.commons.io.Charsets
commons-io.jar:org.apache.commons.io.comparator.AbstractFileComparator
commons-io.jar:org.apache.commons.io.comparator.CompositeFileComparator
commons-io.jar:org.apache.commons.io.comparator.DefaultFileComparator
commons-io.jar:org.apache.commons.io.comparator.DirectoryFileComparator
commons-io.jar:org.apache.commons.io.comparator.ExtensionFileComparator
commons-io.jar:org.apache.commons.io.comparator.LastModifiedFileComparator

ใน windows คุณสามารถใช้ powershell:

Get-ChildItem -File -Filter *.jar |
ForEach-Object{
    $filename = $_.Name
    Write-Host $filename
    $classes = jar -tf $_.Name |Select-String -Pattern '.class' -CaseSensitive -SimpleMatch
    ForEach($line in $classes) {
       write-host $filename":"(($line -replace "\.class", "") -replace "/", ".")
    }
}

0

คำอธิบายของโซลูชัน : Eclipse IDE สามารถใช้ได้โดยการสร้างโปรเจ็กต์ java ตัวอย่างและเพิ่ม jars ทั้งหมดในพา ธ Project Build

ขั้นตอนด้านล่าง :

  1. สร้างโปรเจ็กต์ Eclipse Java ตัวอย่าง

  2. ขวดทั้งหมดที่คุณมีใน Build Path

  3. CTRL + SHIFT + T แล้วพิมพ์ชื่อคลาสเต็ม

  4. ผลลัพธ์จะแสดงในหน้าต่างพร้อมกับขวดทั้งหมดที่มีคลาสนั้น ดูรูปภาพที่แนบมา ใส่คำอธิบายภาพที่นี่


0

windows cmd: สิ่งนี้จะใช้ได้ถ้าคุณมี te jars ทั้งหมดในไดเร็กทอรีเดียวกันและดำเนินการคำสั่งด้านล่าง

for /r %i in (*) do ( jar tvf %i | find /I "search_string")

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.