2012-06-06 20 views
8

我需要包含在我的Java源代碼包中的所有類文件的Class []。在Java中獲取一個包中的類文件數組

我無法找到一個標準方法來完成一次。如果有人可以編寫一個函數來獲取該列表將非常有幫助。

Class[] myClasses = yourfunction(); // Return a list of class inside a source package in the currently working project in java 
+0

沒有標準方法來枚舉給定包中的所有類。在某些情況下,它甚至不可能(想象一下URLClassLoader從HTTP URL加載類:沒有標準方法來枚舉文件夾中的文件)。 –

+1

請參閱這裏手動解決方法(這不是傻瓜證明) - http://stackoverflow.com/questions/176527/how-can-i-enumerate-all-classes-in-a-package-and-add-them-一個清單 – Perception

回答

7

我能夠使用正常的文件I/O和搜索機制來解決這個問題。你可以查看這裏發佈的答案。

private static List<Class> getClassesForPackage(Package pkg) { 
    String pkgname = pkg.getName(); 

    List<Class> classes = new ArrayList<Class>(); 

    // Get a File object for the package 
    File directory = null; 
    String fullPath; 
    String relPath = pkgname.replace('.', '/'); 

    //System.out.println("ClassDiscovery: Package: " + pkgname + " becomes Path:" + relPath); 

    URL resource = ClassLoader.getSystemClassLoader().getResource(relPath); 

    //System.out.println("ClassDiscovery: Resource = " + resource); 
    if (resource == null) { 
     throw new RuntimeException("No resource for " + relPath); 
    } 
    fullPath = resource.getFile(); 
    //System.out.println("ClassDiscovery: FullPath = " + resource); 

    try { 
     directory = new File(resource.toURI()); 
    } catch (URISyntaxException e) { 
     throw new RuntimeException(pkgname + " (" + resource + ") does not appear to be a valid URL/URI. Strange, since we got it from the system...", e); 
    } catch (IllegalArgumentException e) { 
     directory = null; 
    } 
    //System.out.println("ClassDiscovery: Directory = " + directory); 

    if (directory != null && directory.exists()) { 

     // Get the list of the files contained in the package 
     String[] files = directory.list(); 
     for (int i = 0; i < files.length; i++) { 

      // we are only interested in .class files 
      if (files[i].endsWith(".class")) { 

       // removes the .class extension 
       String className = pkgname + '.' + files[i].substring(0, files[i].length() - 6); 

       //System.out.println("ClassDiscovery: className = " + className); 

       try { 
        classes.add(Class.forName(className)); 
       } catch (ClassNotFoundException e) { 
        throw new RuntimeException("ClassNotFoundException loading " + className); 
       } 
      } 
     } 
    } else { 
     try { 
      String jarPath = fullPath.replaceFirst("[.]jar[!].*", ".jar").replaceFirst("file:", ""); 
      JarFile jarFile = new JarFile(jarPath); 
      Enumeration<JarEntry> entries = jarFile.entries(); 
      while (entries.hasMoreElements()) { 
       JarEntry entry = entries.nextElement(); 
       String entryName = entry.getName(); 
       if (entryName.startsWith(relPath) && entryName.length() > (relPath.length() + "/".length())) { 

        //System.out.println("ClassDiscovery: JarEntry: " + entryName); 
        String className = entryName.replace('/', '.').replace('\\', '.').replace(".class", ""); 

        //System.out.println("ClassDiscovery: className = " + className); 
        try { 
         classes.add(Class.forName(className)); 
        } catch (ClassNotFoundException e) { 
         throw new RuntimeException("ClassNotFoundException loading " + className); 
        } 
       } 
      } 
     } catch (IOException e) { 
      throw new RuntimeException(pkgname + " (" + directory + ") does not appear to be a valid package", e); 
     } 
    } 
    return classes; 
} 
+4

Soooo大,必須有一個更簡單的方法... – Illidanek

+0

@Illidanek你可以絕對減少這段代碼的一些代碼行,也可能存在一個更好的解決方案,即使我想看到一些更短,效率更高的代碼可以完成相同的工作。 – AurA

+0

好的答案...保存了我很多的時間 –

3

沒試過這對所有的虛擬機,但在最近的Oracle VM有一個較短的方式:

Enumeration<URL> resources = Thread.currentThread().getContextClassLoader().getResources("package/name/with/slashes/instead/dots"); 
    while (resources.hasMoreElements()) { 
     URL url = resources.nextElement(); 
     System.out.println(url); 
     System.out.println(new Scanner((InputStream) url.getContent()).useDelimiter("\\A").next()); 
    } 

這將打印出包中的資源的名稱,這樣你就可以使用getResource(...)就可以了。呼叫url.getContent()將返回一個虛擬機特定類sun.net.www.content.text.PlainTextInputStream的實例。

+2

這不適用於jdk 1.8下的jar。 'sun.net.www.protocol.jar.JarURLConnection $ JarURLInputStream'拋出NPE嘗試讀取它。 – Vadzim

相關問題