2012-05-26 13 views
10

Desidero compilare la sorgente senza avere le dipendenze presenti sulla macchina.
esempio: file A.java:
JavaCompiler con ClassLoader e FileManager personalizzati

import some.pkg.B; 
public class A extends B {...} 

non ho fonte B presenti, desidero agganciare sia JavaFileManager o un ClassLoader personalizzato al fine di ottenere i simboli in questione (il pacchetto 'un po'. pacchetto 'e classe B) e quindi utilizzare un servizio che ho che recupera la stringa di origine.

Il codice di compilazione: (inputFiles ha A.java)

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 
CustomClassLoader classLoader = new CustomClassLoader(); 
StandardJavaFileManager standardfileManager = compiler.getStandardFileManager(this, null, null); 
JavaFileManager fileManager = new CustomFileManager(standardfileManager, output, classLoader); 
CompilationTask task = compiler.getTask(null, fileManager, this, null, null, inputFiles); 
boolean result = task.call(); 

Ganci su JavaFileManager (getFileForInput ..) e sul mio programma di caricamento classe (findClass, loadClass ..) non si attivano durante la compilazione ed io ottenuto messaggi di errore:

A.java:#: package some.pkg does not exist 
A.java:#: cannot find symbol 
symbol: class B 

EDIT

Dopo aver suonato in giro con l'API, andando oltre JavaCompiler (vecchia versione) s ource and reading Compilation Overview Non riesco ancora a trovare un hook API che posso usare per fornirmi i simboli dagli alberi di sintassi. Sembra che l'API abbia bisogno di ottenere tutte le risorse basate sui nomi dei pacchetti come suggerito da kschneid.
Una soluzione a cui ho pensato è eseguire JavaCompiler e analizzare i messaggi di errore per i simboli mancanti. In questo modo saprò quali simboli sono necessari, li prendo e ricompilare.
Eventuali altri accorgimenti/soluzioni?

+0

Che JDK versione/compilatore e la piattaforma stai usando? – matts

+0

JavaCompiler (javac), JDK 1.6.30 x64 su Windows. –

+0

Non ne sono completamente sicuro. Ma, mi sento come se quello che stai cercando di fare è il caricamento dinamico della classe. Non puoi usare 'Class.forname()' per caricare la classe in fase di runtime. Per favore correggimi se ho frainteso. – Ankit

risposta

4

(suppongo che non sei davvero utilizza un nome di un pacchetto di "pacchetto", dal momento che sarebbe solo essere illegale ...)

vostra abitudine JavaFileManager dovrebbe essere sempre il suo metodo list invocato. Speriamo che questa notazione ha un senso, ma la combinazione di args a tale metodo dovrebbe essere simile a questo:

[PLATFORM_CLASS_PATH, some, [CLASS], false] 
[CLASS_PATH, some, [SOURCE, CLASS], false] 
[PLATFORM_CLASS_PATH, some.pkg, [CLASS], false] 
[CLASS_PATH, some.pkg, [SOURCE, CLASS], false] 

io non sono sicuro di come difficile sarà per l'ambiente specifico di creare le opportune Iterable<JavaFileObject> casi, ma penso è quello che sarebbe richiesto ...

+0

Grazie per la nota sul pacchetto, ho rivisto la domanda. –

+0

Ho perso questa funzione, buona chiamata.È un buon percorso, ma non voglio creare JavaFileObject su tutte le classi del pacchetto, solo quelle che sono utilizzate nella compilazione attuale del file Java che sto cercando di compilare. C'è un modo per ottenere i nomi delle classi reali e non solo i pacchetti? –

+0

Ecco una grande implementazione per questo. http://atamur.blogspot.kr/2009/10/using-built-in-javacompiler-with-custom.html – zeodtr

1

Ho trovato che un buon modo per agganciare le classi in fase di compilazione è con Groovy AST Transformation. Si può avere uno sguardo a cosa si può fare here

Questo non è semplice vecchia java, però, ma può essere uno strumento utile per conoscere