2012-07-23 34 views
38

Tôi đang sử dụng một số mã của bên thứ ba mà khi đưa ra một đối số dòng lệnh '-classpath' không thiết lập java.class.path, nhưng thay vì chỉ tạo một trình nạp lớp, hãy thêm tất cả các url cho các mục trên dòng lệnh được chỉ định classpath trình nạp lớp, và sau đó đặt nó làm trình nạp lớp ngữ cảnh. Trong một lớp plugin cho mã này mà tôi đã viết, tôi nhận được một thể hiện của trình nạp lớp này, và bằng cách nào đó cần sử dụng nó để lấy lại đường dẫn lớp cơ sở, để tôi có thể sử dụng nó trong một lời gọi của JavaCompiler.getTask (.. .) và biên dịch một số mã khác trên bay. Tuy nhiên có vẻ như không có anyway để có được ClassPath từ ClassLoader, và như java.class.path là unset, tôi dường như không thể truy cập classpath cơ bản mà ứng dụng ban đầu được gọi với ... ?Làm thế nào để có được classpath từ classloader?

Trả lời

50

Nếu trình nạp lớp sử dụng URL, nó phải là URLClassloader. Những gì bạn có quyền truy cập là các URL xác định đường dẫn lớp học cho nó cùng với phụ huynh ClassLoader.

Để có được URL, bạn chỉ cần làm như sau:

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

Làm việc, nhờ :) –

+0

Bạn đang chào đón! –

7

Để tham khảo trong tương lai, trong trường hợp bạn cần phải vượt qua trong đường dẫn lớp để 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

Trong trường hợp câu trả lời khác don Không hoạt động, hãy thử cách này:

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

Các câu trả lời khác là đúng trong hầu hết các trường hợp, nhưng nó trở nên phức tạp hơn trong một số cài đặt: ví dụ: Maven, Tomcat và JUnit có hỗ trợ classpath riêng của họ và họ không sử dụng classpath hệ thống.

Cho đến nay đây là hệ thống hoàn chỉnh nhất mà tôi đã quản lý để đưa ra (mã này là từ dự án Fast Classpath Scanner của tôi):

/** 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

Chắc chắn câu trả lời hoàn chỉnh nhất và tích cực phát triển nếu bạn làm theo dự án. –

+0

Phương pháp bẩn đó tìm kiếm bất kỳ trình nạp lớp khác trên ngăn xếp cuộc gọi chính xác là những gì tôi cần! Cám ơn rất nhiều! – FelipeKunzler

+0

@ luke-hutchison thư viện của bạn là một người tiết kiệm cuộc sống! Đối với bất cứ ai muốn một giải pháp mà được classpath cho một loạt các môi trường thời gian chạy này là tốt nhất hiện có. – Dan

0

Drop mã này vào một trang jsp trống để xem hệ thống phân cấp classloader và liên kết lọ được nạp ở mỗi cấp.

lần() phương pháp dưới đây có thể cũng được sử dụng ngày của riêng mình

<%! 
    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> 
Các vấn đề liên quan