Compilazione Java in-memory, in-memory per Java 5 e Java 6

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

Prima di dar fuoco a questo, ho esaminato le implementazioni esistenti:

  • La maggior parte si basa sull’API del compilatore Java 6.
  • Quelli che non lo fanno, si basano su trucchi.
  • Sì, ho controllato commons-jci. O sono troppo denso per capire come funziona, o semplicemente no.
  • Non riuscivo a trovare il modo di alimentare il compilatore il mio attuale percorso di class (che è abbastanza grande).
  • 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 su Google non riesco a trovare nulla che assomigli a qualità di mezza produzione (eccetto jci, che, come ho già detto, non sono riuscito a utilizzare).

Modificare:

  • Ho guardato su JavaAssist – ho bisogno di classi interne, supporto a livello di lingua Java 5.0 e la compilazione dell’intero classpath. Inoltre, mi piacerebbe creare nuove classi al volo. Potrei sbagliarmi, ma non sono riuscito a trovare come farlo con JavaAssit.
  • Sono disposto ad usare una soluzione basata su file system (chiamata javac) ma non so come divinare il classpath, né come caricare in seguito i file (che non sono nel mio classpath) 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 “valutare”. Apparentemente fa tutto ciò di cui ho bisogno (ottenere una stringa, valutarla nel contesto del classpath ‘corrente’. Manca alcune delle funzionalità di Java 5, ma può usare enum (non definire) e compilare ‘generico’ (cancellato ) classi, quindi dovrebbe essere sufficiente per quello che voglio.

    Non voglio segnare la risposta come accettata sin da quando spero che emerga una soluzione migliore.

    Edit3: accettato il suggerimento di beanshell – funziona davvero meravigliosamente.

    Se non sei completamente legato alla compilazione, soluzioni come Beanshell, Groovy e gli altri linguaggi di scripting sono facilmente incorporati (in realtà, java ha il supporto integrato per colbind un linguaggio di scripting in modo che il tuo codice non sappia nemmeno quale lingua la sceneggiatura è scritta in)

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

    JCI sembra a posto. Questo snippet 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 

    Qualsiasi motivo questo non dovrebbe funzionare?


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

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

    Potresti anche dare un’occhiata a Janino.

    Dal loro sito web:

    Janino è un compilatore che legge un’espressione JavaTM, un blocco, un corpo della class, un file sorgente o un set di file sorgente e genera un bytecode JavaTM che viene caricato ed eseguito direttamente. Janino non è destinato a essere uno strumento di sviluppo, ma un compilatore incorporato per scopi di compilazione in fase di esecuzione, ad es. Analizzatori di espressioni o motori di pagine di server come JSP.

    http://www.janino.net/

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

    Javassist potrebbe interessarti

    Esegui all’interno di un contenitore web come Tomcat e prima generi una pagina JSP, quindi richiamala.

    Ciò ti consente anche di eliminare le vecchie definizioni di class semplicemente sovrascrivendo la pagina JSP anziché far funzionare lentamente il tuo programma di caricamento class.

    Il requisito “in memoria” è dovuto alla velocità o a causa della mancata modifica della base del codice?

    ECJ Eclipse Java Compiler

    Eclipse fornisce e utilizza il proprio compilatore che non è javac

    • Il compilatore Eclipse è utilizzato all’interno dell’IDE (Eclipse)
    • Il compilatore Eclipse può anche essere utilizzato come compilatore batch puro all’esterno di Eclipse

    Compilare un file sorgente

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