Sto usando un codice di terze parti che quando viene fornito un argomento della riga di comando '-classpath' non imposta java.class.path, ma crea semplicemente un classloader, aggiunge tutti gli URL per gli elementi nella riga di comando percorso di classe specificato a il classloader e quindi lo imposta come il classloader di contesto. In una classe plugin di questo codice che ho scritto, ottengo un'istanza di questo classloader e in qualche modo ho bisogno di usarlo per recuperare il classpath sottostante, in modo che possa usarlo in un'invocazione di JavaCompiler.getTask (.. .) e compilare qualche altro codice al volo. Tuttavia non sembra esserci comunque per ottenere ClassPath da ClassLoader, e poiché java.class.path non è impostato, non riesco ad accedere al classpath sottostante a cui l'applicazione è stata inizialmente invocata con ... Qualsiasi idea ?Come ottenere classpath da classloader?
risposta
Se il classloader utilizza URL, deve essere un URLClassloader
. Quello a cui si ha accesso è l'URL che definisce il classpath per esso insieme al genitore ClassLoader
.
Per ottenere gli URL, è sufficiente effettuare le seguenti operazioni:
((URLClassLoader) (Thread.currentThread().getContextClassLoader())).getURLs()
Per riferimento futuro, nel caso in cui è necessario passare nel percorso di classe per 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");
Nel caso in cui altre risposte don 't lavoro, provate questo:
ClassLoader cl = ClassLoader.getSystemClassLoader();
URL[] urls = ((URLClassLoader) cl).getURLs();
for (URL url: urls) {
System.out.println(url.getFile());
}
Le altre risposte sono corrette nella maggior parte delle situazioni, ma diventa più complicato di così in alcune impostazioni: ad es. Maven, Tomcat e JUnit dispongono del proprio supporto del classpath e non utilizzano il classpath di sistema.
Finora questo è il sistema più completo sono riuscito a venire con (questo codice è dal mio progetto 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;
}
Sicuramente la risposta più completa e in continua evoluzione se segui il progetto. –
Quel metodo sporco che cerca qualsiasi altro classloader nello stack delle chiamate era esattamente ciò di cui avevo bisogno! Grazie mille! – FelipeKunzler
@ luke-hutchison la tua biblioteca è un risparmiatore di vita! Per chiunque desideri una soluzione che ottenga classpath per una varietà di ambienti di runtime, questo è il migliore in circolazione. – Dan
goccia di questo codice in una pagina jsp vuota per visualizzare gerarchia dei classloader e associato vasi caricati ad ogni livello.
visita() il metodo di seguito potrebbe anche essere utilizzato da 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>
- 1. Come utilizzare ClassLoader personalizzato?
- 2. Primavera-boot da classpath
- 3. Come si utilizza Java ClassLoader per caricare un file dal classpath?
- 4. Come caricare l'immagine per Android ImageView da classpath?
- 5. ClassLoader getResourceAsStream restituisce null
- 6. Come ottenere il classloader per un pacchetto in equinozio?
- 7. Ottenere tutte le classi nel Classpath
- 8. Change classloader
- 9. Come si "chiude" un ClassLoader?
- 10. Impostazione del modello di venditore da classpath
- 11. Caricamento di file con ClassLoader
- 12. lanciato attraverso il classloader?
- 13. Che cos'è un classloader isolato in Java?
- 14. OSGi: come garantire la coerenza del classpath?
- 15. Scaricare un classloader
- 16. Comprendere le dichiarazioni classpath Eclipse
- 17. Ottenere un elenco di tutti i classloader in una JVM
- 18. Creare script con classpath da SBT
- 19. Ignora .classpath e .project da Git
- 20. Java ClassLoader cambiamento
- 21. java classloader e compilazione runtime
- 22. ClassLoader con chiamata RMI
- 23. Come configurare JBOSS 5.1.0 GA ClassLoader
- 24. classloader Scala confusione
- 25. Perché groovy non usa l'argomento classpath?
- 26. Crea nuovo ClassLoader per ricaricare Classe
- 27. Come aggiungere risorse al classpath
- 28. utente ClassLoader definite in C#
- 29. Quale classloader usare con Parcel.readHashMap?
- 30. Embedded Scala REPL eredita il classpath genitore
ha funzionato, grazie :) –
Sei il benvenuto! –