2013-04-09 35 views
10

Tôi đang tìm cách liệt kê tất cả các gói con của một gói tùy ý trong Java.Liệt kê tất cả các gói con của gói

Something như thế này:

Package basePackage = getPackage("com.mypackage"); 
for(Package subPackage : basepackage.getSubPackages()){ 
    System.out.println(subPackage.getName()); 
} 

Có cách nào để làm điều đó? Cảm ơn trước.

IDE (giả sử Netbeans) làm như thế nào? enter image description here

UPDATE:

Tôi cố gắng để tìm thấy tất cả các gói mappers cho MyBatis. Trong dự án của tôi, tất cả các gói bản đồ phải đặt tên là "* .mappers". Ví dụ: "a.b.mappers" hoặc "a.b.c.mappers". Vấn đề là tôi chỉ biết gói cơ sở, và không chắc chắn có bao nhiêu người lập bản đồ gói theo nó.

UPDATE: Đây là mã của tôi cố gắng sử dụng thư viện phản ánh để làm điều đó:

private Set<String> getPackagesNames() { 
    Reflections reflections = new Reflections("com.mypackage"); 
    Set<Class<? extends Object>> allClasses = reflections.getSubTypesOf(Object.class); 
    Set<String> packageNames = new HashSet<>(); 

    for(Iterator<Class<? extends Object>> it = allClasses.iterator(); it.hasNext();) { 
     Class<? extends Object> subClass= it.next(); 
     packageNames.add(subClass.getPackage().getName()); 
    } 

    return packageNames; 
} 

Không chắc tại sao điều này không hoạt động. Không lớp được tìm thấy ở đây ....

CẬP NHẬT

Đây là mã của tôi để làm điều đó. Loại chậm, nhưng hiệu suất không phải là mối quan tâm lớn trong trường hợp của tôi. Tôi chưa bao giờ sử dụng Spring trước đây, vì vậy nếu có cách tốt hơn để làm điều đó, hãy cho tôi biết. Cảm ơn.

private static Set<String> getPackages(String basePackage) throws IOException, ClassNotFoundException { 
     Set<String> packagesNames = new HashSet<>(); 

     ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); 
     MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resourcePatternResolver); 

     String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + resolveBasePackage(basePackage) + "/" + "**/*.class"; 
     Resource[] resources = resourcePatternResolver.getResources(packageSearchPath); 
     for(Resource resource : resources) { 
       MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(resource);  
       Class aClass = Class.forName(metadataReader.getClassMetadata().getClassName()); 
       String packageName = aClass.getPackage().getName(); 
       packagesNames.add(packageName); 
      } 
     } 
     return packagesNames; 
    } 

    private static String resolveBasePackage(String basePackage) { 
     return ClassUtils.convertClassNameToResourcePath(SystemPropertyUtils.resolvePlaceholders(basePackage)); 
    } 

Hầu hết các mã được sao chép từ How do I read all classes from a Java package in the classpath?

+1

bạn có thấy điều này không: http://stackoverflow.com/questions/4212088/java-programmatically-determine-all-of-the-package-names-loaded-on-the-classpa – Azodious

Trả lời

0

1) Tải bất kỳ lớp từ gói và nhận được URL của nó

URL u = Test.class.getResource(""); 

2) Xác định nếu nó là một tập tin hoặc jar.

2) sử dụng File.list() cho thư mục hoặc JarFile.getEntries cho jar để tìm các gói con

+0

... điều này giả định tất cả của các lớp khác trong gói nằm trong cùng một jar (đúng 99% thời gian, nhưng vẫn ..) – radai

+0

Điều đó cũng sẽ chạy khác trong các lần chạy thử Maven, vì Maven chỉ thêm mã kiểm tra được biên dịch khi chạy trong phạm vi kiểm tra. Tất nhiên, không có kết nối giữa các gói và các gói con, do đó, nhiệm vụ này có vẻ hơi lạ. –

+0

@Evgeniy Dorofeev làm cách nào để bạn xác định xem URL này có phải là tệp hay bình không. Cảm ơn. – Xin

6

Tôi cho rằng cách dễ nhất để có được gói là để có được tất cả các gói của bộ nạp lớp của bạn với

Package.getPackages() 

và lọc nó với tên gói của bạn với

packageName.startsWith("com.yourcompany.yourpackage") 
+0

Mẹo tuyệt vời! Tôi đang làm việc với một dự án không thể có nhiều phụ thuộc hơn và đây là một giải pháp thực sự tốt, nhẹ, mặc dù tôi chưa sử dụng nó. – gustavohenke

+0

Như đã lưu ý trên http://stackoverflow.com/a/13944677/421602, điều này cung cấp cho bạn tất cả các gói đã biết (!) Tới trình nạp lớp hiện tại - vì vậy nếu bạn chưa truy cập một lớp trong một gói nhất định, nó đã thắng không nằm trong danh sách này. – vorburger

0

Một cách khác có thể giải quyết vấn đề này sẽ được sử dụng classloader hệ thống để tải tất cả lọ/file zip trong các classpath và sau đó chỉ đơn giản là kiểm tra những.

Hiệu suất sẽ không tuyệt vời. Bởi vì chúng tôi đang kiểm tra các tệp jar/zip, nhưng nó hoạt động.

Dưới đây là một số mã ví dụ:

import java.net.URL; 
import java.net.URLClassLoader; 
import java.nio.file.Files; 
import java.nio.file.Paths; 
import java.util.Arrays; 
import java.util.LinkedHashSet; 
import java.util.Set; 
import java.util.TreeSet; 
import java.util.jar.JarInputStream; 
import java.util.stream.Collectors; 
import java.util.zip.ZipEntry; 

public class ClasspathLister { 

    public static void main(String[] args) { 
     listPackages("com/fasterxml").forEach(s -> { 
      System.out.printf("%s%n", s.replace("/", ".").replaceAll("\\.$", "")); 
     }); 
    } 

    private static Set<String> listPackages(String prefix) { 
     URLClassLoader sysloader = (URLClassLoader) ClassLoader.getSystemClassLoader(); 
     return Arrays.stream(sysloader.getURLs()) 
      .filter(u -> u.toString().matches("(?i).+(\\.jar|\\.zip)$")) 
      .flatMap(u -> listJar(u, prefix).stream()) 
      .collect(Collectors.toCollection(TreeSet::new)); 
    } 

    private static Set<String> listJar(URL u, String prefix) { 
     Set<String> packages = new LinkedHashSet<>(); 
     try (JarInputStream in = 
      new JarInputStream(Files.newInputStream(Paths.get(u.toURI())))) { 
      ZipEntry ze; 
      while ((ze = in.getNextEntry()) != null) { 
       if (ze.isDirectory() && ze.getName().startsWith(prefix)) { 
        packages.add(ze.getName()); 
       } 
      } 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
     return packages; 
    } 
} 

Sản lượng này sẽ giống như thế:

com.fasterxml 
com.fasterxml.jackson 
com.fasterxml.jackson.annotation 
com.fasterxml.jackson.core 
com.fasterxml.jackson.core.base 
com.fasterxml.jackson.core.filter 
com.fasterxml.jackson.core.format 
com.fasterxml.jackson.core.io 
com.fasterxml.jackson.core.json 
com.fasterxml.jackson.core.sym 
com.fasterxml.jackson.core.type 
com.fasterxml.jackson.core.util 
com.fasterxml.jackson.databind 
com.fasterxml.jackson.databind.annotation 
com.fasterxml.jackson.databind.cfg 
com.fasterxml.jackson.databind.deser 
com.fasterxml.jackson.databind.deser.impl 
com.fasterxml.jackson.databind.deser.std 
com.fasterxml.jackson.databind.exc 
... 
0

Xây dựng: IDE thực sự đọc các tập tin JAR của sự phụ thuộc.Trong tệp JAR nó chỉ là một cấu trúc thư mục. Điều này khác với cách mà Java ClassLoader lưu trữ nó.

Các vấn đề liên quan