Làm cách nào để lấy tên các lớp bên trong tệp jar?


112

Tôi có một tệp JAR và tôi cần lấy tên của tất cả các lớp bên trong tệp JAR này. Làm thế nào tôi có thể làm điều đó?

Tôi truy cập vào nó và thấy một cái gì đó về JarFile hoặc Java ClassLoadernhưng tôi không biết làm thế nào để làm điều đó.


Bạn có đang sử dụng một số IDE không? Vì nó sẽ tự động hiển thị nếu bạn đang sử dụng một IDE.
joey rohan

Tôi đang sử dụng Eclipse, nhưng tôi cần thực hiện việc này bằng mã.
sticku,

@LuiggiMendoza - Bản sao tiềm năng có câu trả lời với các ví dụ cũng như tài nguyên cho tài liệu. Tìm kiếm một trong những tên lớp + ví dụ đó sẽ mang lại một số kết quả hữu ích.
Aiias

@Alias ​​bản sao có thể nêu cách tìm và lấy một tệp từ một jar, trong khi câu hỏi là về việc lấy tên lớp bên trong một jar (có thể là các lớp trong tất cả các gói bên trong nó). Liên kết trong câu trả lời của ErikKaju chỉ ra một giải pháp khả thi bằng cách sử dụng JarInputStreamJarEntrycác lớp mà tôi không thể tìm thấy trong bất kỳ câu trả lời nào của liên kết được giới thiệu của bạn.
Luiggi Mendoza

Câu trả lời:


68

Thật không may, Java không cung cấp một cách dễ dàng để liệt kê các lớp trong JRE "bản địa". Điều đó khiến bạn có một số tùy chọn: (a) đối với bất kỳ tệp JAR nào đã cho, bạn có thể liệt kê các mục nhập bên trong tệp JAR đó, tìm các .classtệp và sau đó xác định mỗi lớp Java.class tệp đại diện; hoặc (b) bạn có thể sử dụng một thư viện thực hiện việc này cho bạn.

Tùy chọn (a): Quét tệp JAR theo cách thủ công

Trong tùy chọn này, chúng tôi sẽ điền vào classNamesdanh sách tất cả các lớp Java có bên trong tệp jar tại /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()));
    }
}

Lựa chọn (b): Sử dụng thư viện phản ánh chuyên biệt

Trái ổi

Ổi đã có ClassPathtừ ít nhất 14.0, mà tôi đã sử dụng và thích. Một điều thú vị ClassPathlà nó không tải các lớp mà nó tìm thấy, điều này rất quan trọng khi bạn đang quét một số lượng lớn các lớp.

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

Suy ngẫm

Cá nhân tôi chưa sử dụng thư viện Reflections , nhưng nó có vẻ rất được yêu thích. Một số ví dụ tuyệt vời được cung cấp trên trang web như cách nhanh chóng này để tải tất cả các lớp trong một gói được cung cấp bởi bất kỳ tệp JAR nào , điều này cũng có thể hữu ích cho ứng dụng của bạn.

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

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

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

Phản xạ không hoạt động nếu chạy từ một jar thực thi.
Luke

Một giải pháp Spring hoạt động từ các lọ thực thi: stackoverflow.com/a/21430849/4265610 .
Luke

1
Chỉ dùng. jar tvf jarfile.jar. Tại sao bạn làm tất cả những điều này cho.
Philip Rego,

183

Bạn có thể sử dụng jarcông cụ Java . Liệt kê nội dung của tệp jar trong tệp txt và bạn có thể thấy tất cả các lớp trong jar.

jar tvf jarfile.jar

-t danh sách mục lục để lưu trữ

-v tạo đầu ra dài dòng trên đầu ra tiêu chuẩn

-f chỉ định tên tệp lưu trữ


1
Cảm ơn. Điều này trả lời phần "chỉ lấy danh sách lớp" của OP không được hỏi.
octopusgrabbus

9
Bạn cũng có thể sử dụng unzip -l jarfile.jartrong một nhúm. Tệp JAR chỉ là tệp zip có tệp kê khai!
ký vào

3
Vấn đề là anh ta có thể muốn lấy các tệp lớp bên trong một jar trong thời gian chạy, với một cá thể của trình nạp lớp (có khả năng xem những lớp nào được tải bên trong jar cụ thể đó).
Richard Duerr

19

Có thể bạn đang tìm kiếm jarlệnh để lấy danh sách các lớp trong thiết bị đầu cuối,

$ 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

Ở đâu,

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

Hoặc, chỉ cần hiển thị kết quả ở trên để xem .classchỉ

$ 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

Để xem số lượng class,

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

2
đây chính xác là những gì tôi cần, ngay cả khi chủ sở hữu câu hỏi cần một giải pháp dựa trên mã. Cảm ơn!
providencemac

10

Đây là một bản hack mà tôi đang sử dụng:

Bạn có thể sử dụng javatính năng tự động hoàn thành của như thế này:

java -cp path_to.jar <Tab>

Điều này sẽ cung cấp cho bạn một danh sách các lớp có sẵn để vượt qua làm lớp bắt đầu. Tất nhiên, cố gắng sử dụng một tệp không có tệp chính sẽ không làm được gì, nhưng bạn có thể thấy những gì cho javarằng các lớp bên trong .jarđược gọi.



5

Bạn co thể thử:

jar tvf jarfile.jar 

Điều này sẽ hữu ích chỉ nếu jar của bạn có thể thực thi được tức là trong tệp kê khai, bạn đã xác định một số lớp là lớp chính


Thêm một số ví dụ cụ thể về lọ ví dụ vào câu trả lời của bạn.
Juru

4

Lệnh dưới đây sẽ liệt kê nội dung của một tệp jar .

lệnh: - unzip -l jarfilename.jar.

mẫu 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

Theo sổ tay của unzip

-l liệt kê các tập tin lưu trữ (định dạng ngắn). Tên, kích thước tệp không nén và ngày giờ sửa đổi của các tệp được chỉ định sẽ được in, cùng với tổng số cho tất cả các tệp được chỉ định. Nếu UnZip được biên dịch với OS2_EAS được định nghĩa, tùy chọn -l cũng liệt kê các cột cho kích thước của các thuộc tính mở rộng OS / 2 được lưu trữ (EA) và danh sách kiểm soát truy cập OS / 2 (ACL). Ngoài ra, nhận xét tệp zip và nhận xét tệp cá nhân (nếu có) được hiển thị. Nếu một tệp được lưu trữ từ hệ thống tệp một trường hợp (ví dụ: hệ thống tệp MS-DOS FAT cũ) và tùy chọn -L được cung cấp, tên tệp sẽ được chuyển đổi thành chữ thường và có tiền tố là dấu mũ (^).


Mặc dù đoạn mã này được hoan nghênh và có thể cung cấp một số trợ giúp, nó sẽ được cải thiện đáng kể nếu nó bao gồm lời giải thích về cách thứclý do tại sao đoạn mã này giải quyết được vấn đề. Hãy nhớ rằng bạn đang trả lời câu hỏi cho độc giả trong tương lai, chứ không chỉ người hỏi bây giờ! Vui lòng chỉnh sửa câu trả lời của bạn để thêm giải thích và đưa ra dấu hiệu về những giới hạn và giả định nào được áp dụng.
Toby Speight

2

Bạn có thể thử điều này:

unzip -v /your/jar.jar

Điều này sẽ hữu ích chỉ nếu jar của bạn có thể thực thi được tức là trong tệp kê khai, bạn đã xác định một số lớp là lớp chính


1

Sử dụng tập lệnh bash này:

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

điều này sẽ liệt kê các lớp bên trong các lọ trong thư mục của bạn ở dạng:

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

Đầu ra mẫu:

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

Trong windows, bạn có thể sử dụng 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

Mô tả Giải pháp : Eclipse IDE có thể được sử dụng cho việc này bằng cách tạo một dự án java mẫu và thêm tất cả các lọ trong đường dẫn Xây dựng dự án

CÁC BƯỚC bên dưới :

  1. Tạo một dự án Java Eclipse mẫu.

  2. Tất cả các lọ bạn có trong Đường dẫn xây dựng của nó

  3. CTRL + SHIFT + T và Nhập tên lớp đầy đủ.

  4. Kết quả sẽ được hiển thị trong cửa sổ với tất cả các lọ có lớp đó. Xem hình đính kèm. nhập mô tả hình ảnh ở đây


0

Windows cmd: Điều này sẽ hoạt động nếu bạn có tất cả các lọ te trong cùng một thư mục và thực hiện lệnh dưới đây

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

0

Mac OS: Trên Terminal:

vim <your jar location>

after jar gets opened, press / and pass your class name and hit enter
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.