10

So che questo è stato chiesto e ho risposto molto ma non ho ancora una buona soluzione e ancora non capisco alcune parti. Quindi ho il requisito di compilare i file * .java a livello di codice.Compilare i file java programmaticamente

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 

è quello che sto usando e (come previsto) il compilatore è null. Ora, so che devo usare il JDK e non il JRE come "runtime", ma qui c'è qualcosa che non capisco: non è sufficiente mettere semplicemente tools.jar nel classpath dell'applicazione e poi avere accesso all'API Java Compiler? Se questo è vero, c'è (credo che ci sia) una differenza tra un'applicazione java stand-alone e un'applicazione basata sul web. In realtà, sto tentando di richiamare JavaCompiler da una webapp di PlayFramework quindi ho capito, forse queste soluzioni (con incluso lo tools.jar) funzionano solo per le applicazioni autonome?

Ho anche cercato di creare un ClassLoader personalizzato e richiamare il metodo di cui sopra con la riflessione, ma tutto quello che sto ottenendo è null per l'oggetto compiler:

ClassLoader classloader = app.classloader(); 
File file = new File("lib/tools.jar");   
URL url = file.toURI().toURL(); 
URL[] urls = new URL[]{url}; 
ClassLoader newCL = new URLClassLoader(urls, classloader) { 
}; 
Class<?> loadClass = newCL.loadClass("javax.tools.ToolProvider"); 
Method method = loadClass.getMethod("getSystemJavaCompiler", null);    
Object object = method.invoke(null); 
System.out.println("Object: " + object); // NULL 

Spiegazione per il codice precedente:

  • Non ho incluso try/catches per motivi di semplicità.
  • app.classloader() è un metodo che restituisce il gioco ClassLoader di App
  • tools.jar è incluso nella mia cartella lib del progetto Play (questo implica che è sul classpath del progetto - in base alla documentazione gioco)

Sono quasi sicuro che c'è qualcos'altro che devo fare prima che Play sia in grado di caricare la classe del compilatore Java. Solo che non so cosa mi manca.

Opzioni come Runtime.exec("javac myFile.java") e il compilatore JDT Eclipse sono noti a me, ma non è quello che sto cercando.

Oh, e qualcosa come System.setProperty("java.home", "PATH_TO_YOUR_JDK"); e poi ToolProvider.getSystemJavaCompiler(); funziona ma trovo questa soluzione così brutta.

migliori saluti

EDIT: (per dare ulteriori informazioni e riflettono l'ultimo stato) Questa è una rappresentazione di base di web-app-struttura:

myApp 
|-conf\... 
|-lib\MyJar.jar 
|-lib\tools.jar 
|-logs\... 
|-... 

MyJar.jar ha ora un file META-INF/MANIFEST.MF con il seguente contenuto:

Manifest-Version: 1.0 
Sealed: true 
Main-Class: here.comes.my.main.class 
Class-Path: tools.jar 

Senza avvio dell'app Play, sto provando (nella cartella lib): java -jar MyJar.jar - il mio semplice metodo main tenta di richiamare il compilatore (ToolProvider.getSystemJavaCompiler();) e restituisce null. Quindi questo mi porta a credere che il problema non ha nulla a che fare con il gioco - Non riesco nemmeno a ottenere un compilatore quando normalmente eseguo il mio Jar!

risposta

0

Si dice nello documentation che To run the Play framework, you need JDK 6 or later. come è riuscito a eseguirlo con jre?

Ad ogni modo, se getSystemJavaCompiler restituisce null significa che non si dispone di tools.jar nel classpath o è danneggiato. Se si tratta di Sun/Oracle java, assicurarsi che contenga la classe com.sun.tools.javac.api.JavacTool.

E se si desidera utilizzare un programma di caricamento classi personalizzato, è la classe JavacTool che è necessario caricare, non ToolProvider. Date un'occhiata al modo in cui lo fa in Java 6:

 URL[] urls = {file.toURI().toURL()}; 
     ClassLoader cl = URLClassLoader.newInstance(urls); 
     cl.setPackageAssertionStatus("com.sun.tools.javac", true); 
     return Class.forName(defaultJavaCompilerName, false, cl); 

dove defaultJavaCompilerName = "com.sun.tools.javac.api.JavacTool"

sottoclasse a JavaCompiler e ottenere nuova istanza - avrete il vostro compilatore.

+0

'JAVA_HOME' è impostato sulla mia macchina di sviluppo, restituendo il percorso al JDK quando richiesto. Ma ottenere la proprietà '" java.home "' dall'esecuzione dell'applicazione Play (con 'System.getProperty (...)') restituisce il percorso di JRE. Quindi forse questo è l'unico problema. Ma non dovrebbe esserci un problema quando ho il 'tools.jar' nel mio classpath. E sono abbastanza sicuro che 'tools.jar' si trova nel mio classpath (controllato durante l'esecuzione dell'app Web) e che il file non sia corrotto. Ho intenzione di provare la roba di classload sopra menzionata. – user2229298

+0

Ho eseguito il gioco su Ubuntu e ho potuto ottenere il compilatore Java da scala senza problemi. Forse c'è qualcosa di sbagliato nella configurazione? –

+0

Appena provato 'JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler(); \t \t \t System.out.println ("Java compiler:" + javaCompiler); 'dal metodo' onStart' in 'app/Global.java' - con' tools.jar' nel classpath della mia app - anche quello sta tornando 'null' – user2229298

1

Non vi è alcuna differenza tra le applicazioni Web e le applicazioni standalone.

Non si deve comprimere tools.jar nel percorso classe webapp. Il classloader in Java generalmente funziona solo dal basso verso l'alto. Quindi il ToolProvider che fa parte di jdk non vedrà il tuo tools.jar nel classpath webapp (non può guardare in basso nel classpath webapp).

Soluzione: utilizzare un JDK e accertarsi di puntarlo o inserire tools.jar in una directory ext di Java. È possibile sovrascrivere la directory ext impostando la proprietà -Djava.ext.dir in qualsiasi directory desiderata.

+0

sembra giusto. Suggerirei di mettere il barattolo degli strumenti in un posto comune o di usare il jdk. – tgkprog

Problemi correlati