Domanda

Come posso compilare il codice java da una stringa arbitraria (in memoria) in Java 5 e Java 6, caricarlo ed eseguire un metodo specifico su di esso (predefinito)?

Prima di accendere questo, ho esaminato le implementazioni esistenti:

  • La maggior parte si affida all'API del compilatore Java 6.
  • Quelli che non lo fanno, si basano su trucchi.
  • Sì, ho verificato commons-jci. O sono troppo denso per capire come funziona, o semplicemente non lo fa.
  • Non sono riuscito a trovare come alimentare il compilatore il mio percorso di classe corrente (che è piuttosto enorme).
  • Sull'implementazione che ha funzionato (in Java 6), non sono riuscito a trovare come caricare correttamente le classi interne (o le classi anonime interne).
  • Mi piacerebbe molto se l'intera cosa fosse in memoria, poiché la cosa funziona su più ambienti.

Sono sicuro che questo è stato risolto in precedenza, ma non riesco a trovare nulla che appaia anche su metà produzione su google (tranne jci, che, come ho già detto, non sono riuscito a utilizzare) .

Modifica:

  • Ho esaminato JavaAssist: ho bisogno di classi interne, supporto a livello di linguaggio Java 5.0 e compilazione con l'intero percorso di classe. Inoltre, vorrei creare nuove classi al volo. io potrebbe essere un errore, ma non sono riuscito a trovare come farlo con JavaAssit.
  • Sono disposto a utilizzare una soluzione basata su file system (chiamata javac) ma non so come divinare il percorso di classe, né come caricare successivamente i file (che non sono nel mio percorso di classe) con uno speciale classloader che può essere riciclato per più invocazioni. Mentre so come ricercarlo, preferirei una soluzione pronta.

Edit2: Per ora, sono contento di BeanShell " valuta " ;. Apparentemente fa tutto ciò di cui ho bisogno per (ottenere una stringa, valutarla nel contesto del percorso di classe "corrente". Manca alcune delle funzionalità di Java 5, ma può usare enum (non definito) e compilato "generico" (cancellato ), quindi dovrebbe essere sufficiente per quello che voglio.

Non voglio contrassegnare la risposta come ancora accettata poiché spero in una soluzione migliore.

Edit3: accettato il suggerimento beanshell - funziona davvero meravigliosamente.

È stato utile?

Soluzione

Se non sei completamente legato alla compilazione, soluzioni come Beanshell, groovy e gli altri linguaggi di scripting sono facilmente incorporabili (in effetti, java ha il supporto integrato per collegare un linguaggio di scripting in modo che il tuo codice non sia nemmeno sapere in quale lingua è scritto lo script)

Beanshell dovrebbe eseguire qualsiasi codice java IIRC al 100%, e credo che Groovy possa eseguire la maggior parte del codice java - probabilmente tutti.

Altri suggerimenti

JCI sembra a posto. Questo frammento di codice dovrebbe essere la tua base:

JavaCompiler compiler = new JavaCompilerFactory().createCompiler("eclipse");

MemoryResourceReader mrr = new MemoryResourceReader();
mrr.add("resource name string", yourJavaSourceString.getBytes());

MemoryResourceStore mrs = new MemoryResourceStore();

CompilationResult result = compiler.compile(sources, mrr, mrs);

// don't need the result, unless you care for errors/warnings
// the class should have been compiled to your destination dir

Qualche motivo per cui non dovrebbe funzionare?


Modifica: aggiunto un MemoryResourceStore per inviare l'output della classe compilato in memoria, come richiesto.

Inoltre, l'impostazione di javac , come classpath nel tuo caso, può essere effettuata tramite setCustomArguments (String [] pCustomArguments) in JavacJavaCompilerSettings class.

Potresti voler dare un'occhiata anche a Janino.

Dal loro sito Web:

Janino è un compilatore che legge un'espressione JavaTM, un blocco, un corpo di classe, un file sorgente o un set di file sorgente e genera un bytecode JavaTM che viene caricato ed eseguito direttamente. Janino non intende essere uno strumento di sviluppo, ma un compilatore incorporato per scopi di runtime, ad es. valutatori di espressioni o "pagine server" motori come JSP.

http://www.janino.net/

Attualmente lo sto usando in un progetto mission-critical piuttosto grande e funziona perfettamente

Javassist potrebbe interessarti

Esegui all'interno di un contenitore Web come Tomcat e genera prima una pagina JSP, quindi invocala.

Ciò ti consente anche di sbarazzarti delle vecchie definizioni di classe semplicemente sovrascrivendo la pagina JSP invece di far funzionare lentamente il tuo classloader.

È il "quotato in memoria" requisito a causa della velocità o per non aver modificato la base di codice?

Compilatore Java ECJ Eclipse

Eclipse fornisce e usa il proprio compilatore che non è javac

  • Il compilatore Eclipse viene utilizzato all'interno dell'IDE (Eclipse)
  • Il compilatore Eclipse può essere utilizzato anche come compilatore batch puro al di fuori di Eclipse

Compila un file sorgente

$ java -jar ecj-3.5.2.jar HelloWorld.java

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top