2012-07-23 50 views
38

我正在使用一些第三方代碼,當給定'-classpath'命令行參數時不會設置java.class.path,而只是創建一個類加載器,將命令行中指定類路徑的所有項目的URL添加到類加載器,然後將其設置爲上下文類加載器。 在我編寫的代碼的插件類中,我得到了這個類加載器的一個實例,並且以某種方式需要使用它來獲取底層類路徑,以便我可以在調用JavaCompiler.getTask(.. 。)並編譯一些其他代碼。 然而,似乎無論如何都不能從ClassLoader獲取ClassPath,並且因爲java.class.path未設置,我似乎無法訪問應用程序最初被調用的基礎類路徑...任何想法?如何從classloader獲取classpath?

回答

50

如果類加載器使用URL,則它必須是URLClassloader。您可以訪問的是其中定義類路徑與其父母ClassLoader並列的URL。

要獲得的URL,只要做到以下幾點:

((URLClassLoader) (Thread.currentThread().getContextClassLoader())).getURLs() 
+0

的工作,謝謝:) – 2012-07-23 16:28:48

+0

不客氣! – 2012-07-23 16:36:47

7

以供將來參考,如果您需要在類路徑傳遞給ProcessBuilder

StringBuffer buffer = new StringBuffer(); 
for (URL url : 
    ((URLClassLoader) (Thread.currentThread() 
     .getContextClassLoader())).getURLs()) { 
    buffer.append(new File(url.getPath())); 
    buffer.append(System.getProperty("path.separator")); 
} 
String classpath = buffer.toString(); 
int toIndex = classpath 
    .lastIndexOf(System.getProperty("path.separator")); 
classpath = classpath.substring(0, toIndex); 
ProcessBuilder builder = new ProcessBuilder("java", 
    "-classpath", classpath, "com.a.b.c.TestProgram"); 
5

如果其他的答案唐沒有工作,試試這個:

ClassLoader cl = ClassLoader.getSystemClassLoader(); 
URL[] urls = ((URLClassLoader) cl).getURLs(); 
for (URL url: urls) { 
    System.out.println(url.getFile()); 
} 
12

其他答案在大多數情況下是正確的,但它在某些設置中變得更復雜:例如Maven,Tomcat和JUnit有它們自己的類路徑支持,它們不使用系統類路徑。

到目前爲止,這是最完整的系統,我已成功地拿出了(此代碼是從我Fast Classpath Scanner項目):

/** The unique elements of the classpath, as an ordered list. */ 
private final ArrayList<File> classpathElements = new ArrayList<>(); 

/** The unique elements of the classpath, as a set. */ 
private final HashSet<String> classpathElementsSet = new HashSet<>(); 

/** Clear the classpath. */ 
private void clearClasspath() { 
    classpathElements.clear(); 
    classpathElementsSet.clear(); 
} 

/** Add a classpath element. */ 
private void addClasspathElement(String pathElement) { 
    if (classpathElementsSet.add(pathElement)) { 
     final File file = new File(pathElement); 
     if (file.exists()) { 
      classpathElements.add(file); 
     } 
    } 
} 

/** Parse the system classpath. */ 
private void parseSystemClasspath() { 
    // Look for all unique classloaders. 
    // Keep them in an order that (hopefully) reflects the order in which class resolution occurs. 
    ArrayList<ClassLoader> classLoaders = new ArrayList<>(); 
    HashSet<ClassLoader> classLoadersSet = new HashSet<>(); 
    classLoadersSet.add(ClassLoader.getSystemClassLoader()); 
    classLoaders.add(ClassLoader.getSystemClassLoader()); 
    if (classLoadersSet.add(Thread.currentThread().getContextClassLoader())) { 
     classLoaders.add(Thread.currentThread().getContextClassLoader()); 
    } 
    // Dirty method for looking for any other classloaders on the call stack 
    try { 
     // Generate stacktrace 
     throw new Exception(); 
    } catch (Exception e) { 
     StackTraceElement[] stacktrace = e.getStackTrace(); 
     for (StackTraceElement elt : stacktrace) { 
      try { 
       ClassLoader cl = Class.forName(elt.getClassName()).getClassLoader(); 
       if (classLoadersSet.add(cl)) { 
        classLoaders.add(cl); 
       } 
      } catch (ClassNotFoundException e1) { 
      } 
     } 
    } 

    // Get file paths for URLs of each classloader. 
    clearClasspath(); 
    for (ClassLoader cl : classLoaders) { 
     if (cl != null) { 
      for (URL url : ((URLClassLoader) cl).getURLs()) { 
       if ("file".equals(url.getProtocol())) { 
        addClasspathElement(url.getFile()); 
       } 
      } 
     } 
    } 
} 

/** Override the system classpath with a custom classpath to search. */ 
public FastClasspathScanner overrideClasspath(String classpath) { 
    clearClasspath(); 
    for (String pathElement : classpath.split(File.pathSeparator)) { 
     addClasspathElement(pathElement); 
    } 
    return this; 
} 

/** 
* Get a list of unique elements on the classpath (directories and files) as File objects, preserving order. 
* Classpath elements that do not exist are not included in the list. 
*/ 
public ArrayList<File> getUniqueClasspathElements() { 
    return classpathElements; 
} 
+1

絕對是最完整的答案,並積極發展,如果你關注這個項目。 – 2015-08-21 10:34:56

+0

在調用堆棧中查找任何其他類加載器的髒方法正是我所需要的!非常感謝! – FelipeKunzler 2016-02-19 19:27:48

+0

@ luke-hutchison你的圖書館是一個拯救生命的人!對於任何想要爲各種運行時環境獲取類路徑的解決方案的人來說,這都是最好的選擇。 – Dan 2016-02-26 02:49:15

0

刪除此代碼到一個空的JSP頁面來查看ClassLoader的層次和相關裝在每個級別的罐子。

訪問()以下方法也可以單獨使用

<%! 
    public void visit(StringBuilder sb, int indent, ClassLoader classLoader) { 
     if (indent > 20 || classLoader == null) 
      return; 
     String indentStr = new String(new char[indent]).replace("\0", " "); 
     sb.append("\n"); 
     sb.append(indentStr); 
     sb.append(classLoader.getClass().getName()); 
     sb.append(":"); 
     if (classLoader instanceof java.net.URLClassLoader) { 
      java.net.URL[] urls = ((java.net.URLClassLoader)classLoader).getURLs(); 
      for (java.net.URL url : urls) { 
       sb.append("\n"); 
       sb.append(indentStr); 
       sb.append(url); 
      } 
     } 
     sb.append("\n"); 
     visit(sb, indent + 1, classLoader.getParent()); 
    } 

%> 

<% 
StringBuilder sb = new StringBuilder(); 
visit(sb,1,this.getClass().getClassLoader()); 
%> 
<pre> 
<%=sb%> 
</pre>