2012-07-23 19 views
38

Estoy utilizando un código de terceros que cuando se le da un argumento de línea de comando '-classpath' no establece el java.class.path, sino que simplemente crea un cargador de clases, agrega todas las direcciones URL para los elementos en la línea de comando especificada classpath para el cargador de clases, y luego lo configura para que sea el cargador de clases de contexto. En una clase de complemento a este código que he escrito, obtengo una instancia de este cargador de clases, y de alguna manera necesito usarlo para recuperar el classpath subyacente, de modo que pueda usarlo en una invocación de JavaCompiler.getTask (.. .) y compilar algún otro código sobre la marcha. Sin embargo, no parece ser de todos modos para obtener el ClassPath del ClassLoader, y como java.class.path está desarmado, parece que no puedo acceder al classpath subyacente con el que se invocó inicialmente la aplicación ... Cualquier idea ?¿Cómo obtener classpath de classloader?

Respuesta

50

Si el cargador de clases usa URLs, debe ser URLClassloader. A lo que tienes acceso es a las URL que definen el classpath junto con su padre ClassLoader.

para obtener el URL, sólo tiene que hacer lo siguiente:

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

funcionado, gracias :) –

+0

De nada! –

7

Para futuras referencias, en caso de tener que pasar en la ruta de clase para 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

En el caso de otras respuestas Don no funciona, intente esto:

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

Las otras respuestas son correctas en la mayoría de las situaciones, pero se vuelve más complicado que eso en algunos entornos: p. Maven, Tomcat y JUnit tienen su propio soporte de classpath y no usan el classpath del sistema.

Hasta ahora, este es el sistema más completo que he logrado llegar a (este código es de mi proyecto 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

Definitivamente la respuesta más completa y en constante evolución si sigues el proyecto. –

+0

¡Ese sucio método que busca cualquier otro clasificador en la pila de llamadas era exactamente lo que necesitaba! ¡Muchas gracias! – FelipeKunzler

+0

@ luke-hutchison ¡su biblioteca es un salvavidas! Para cualquiera que desee una solución que obtenga classpath para una variedad de entornos de tiempo de ejecución, esto es lo mejor que hay. – Dan

0

gota este código en una página JSP vacía para ver la jerarquía del cargador de clases y asociados frascos cargados en cada nivel.

visita() método siguiente también podría ser utilizado por sí solo

<%! 
    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> 
Cuestiones relacionadas