2008-11-08 13 views
6

Mein Anwendungsfall kompiliert generierte Quelldateien aus einem Java-Programm mit den Klassen ToolProvider und JavaCompiler in JDK 6. Die Quelldateien enthalten Verweise auf Klassen im Context Classloader (es läuft in einem J2EE-Container), aber nicht im System Klassenlader. Nach meinem Verständnis erstellt der ToolProvider standardmäßig die JavaCompiler-Instanz mit dem System-Classloader.Wie verwende ich JDK6 ToolProvider und JavaCompiler mit dem Context Classloader?

Gibt es eine Möglichkeit, einen Klassenlader für JavaCompiler zu spezifizieren?

habe ich versucht, diesen Ansatz, von etwas auf IBM Developerworks geändert:

FileManagerImpl fm = 
    new FileManagerImpl(compiler.getStandardFileManager(null, null, null);); 

mit FileManagerImpl wie folgt definiert:

static final class FileManagerImpl 
    extends ForwardingJavaFileManager<JavaFileManager> { 

    public FileManagerImpl(JavaFileManager fileManager) { 
     super(fileManager); 
    } 

    @Override 
    public ClassLoader getClassLoader(JavaFileManager.Location location) { 
     new Exception().printStackTrace(); 
     return Thread.currentThread().getContextClassLoader(); 
    } 

} 

Der Stacktrace gibt es nur einmal während Annotation Verarbeitung aufgerufen wird. Ich habe überprüft, dass die Klasse, auf die in der Quelldatei verwiesen wird, die kompiliert werden soll, nicht auf dem Systemklassenpfad liegt, sondern aus dem Kontextklassenlader verfügbar ist.

Antwort

1

Eine andere Option ist Commons JCI zu verwenden.

+0

Es scheint nicht, dass JCI Ihnen erlaubt, einen Klassenlader nur in Pfaden zu übergeben, genau wie es die JDK6-Unterstützung erlaubt. – Phil

+0

Wo haben Sie gesucht? Sicher tut es. – tcurdt

8

Wenn Sie den Classpath auf die Dateien kennen, die dem contextclassloader bekannt sind, können Sie sie an den Compiler übergeben:

StandardJavaFileManager fileManager = compiler.getStandardFileManager(this /* diagnosticlistener */, null, null); 
// get compilationunits from somewhere, for instance via fileManager.getJavaFileObjectsFromFiles(List<file> files) 
List<String> options = new ArrayList<String>(); 
options.add("-classpath"); 
StringBuilder sb = new StringBuilder(); 
URLClassLoader urlClassLoader = (URLClassLoader) Thread.currentThread().getContextClassLoader(); 
for (URL url : urlClassLoader.getURLs()) 
    sb.append(url.getFile()).append(File.pathSeparator); 
options.add(sb.toString()); 
CompilationTask task = compiler.getTask(null, fileManager, this /* diagnosticlistener */, options, null, compilationUnits); 
task.call(); 

Dieses Beispiel geht von einer URLClassLoader verwenden (die Sie den Classpath abrufen können) aber du könntest deinen eigenen Klassenpfad einfügen, wenn du willst.

0

Sie stellen zwei separate Fragen hier.

Man kann Klassen kompilieren, die nicht im Systemklassenpfad gefunden werden. Dies kann leicht gelöst werden, indem das Befehlszeilenargument "-classpath" an den Compiler übergeben wird (wie von Leihca erstmals erwähnt).

Die zweite ist, wie ToolProvider und JavaCompiler auf dem Threadkontext Classloader instanziieren. Zum Zeitpunkt dieses Schreibens ist dies eine ungelöste Frage: Using javax.tools.ToolProvider from a custom classloader?