Comstackr le code entièrement en mémoire avec javax.tools.JavaComstackr

J’utilise le JavaComstackr du package javax.tools (JDK 1.7) pour comstackr certaines choses à la volée, comme ceci:

comstackr.run(null, null, "-cp", paths, "path/to/my/file.java"); 

Cela fonctionne mais j’aimerais tout faire en mémoire (par exemple, passer une chaîne avec le code, pas le fichier source, et récupérer le code d’octet, pas un fichier .class). J’ai trouvé que l’extension des parameters InputStream et OutputStream ne sert à rien, car c’est probablement la même chose que dans la console. Savez-vous comment faire fonctionner la méthode run comme ça? Ou connaissez-vous un moyen confirmé de le faire avec la méthode getTask() ? (l’extension de FileManager semble facile, mais n’est-ce pas facile 🙂

J’ai exécuté le code ci-dessus dans Mac OS Java 7. Aucun d’entre eux ne fonctionne. J’ai donc écrit un https://github.com/trung/InMemoryJavaComstackr

 SsortingngBuffer sourceCode = new SsortingngBuffer(); sourceCode.append("package org.mdkt;\n"); sourceCode.append("public class HelloClass {\n"); sourceCode.append(" public Ssortingng hello() { return \"hello\"; }"); sourceCode.append("}"); Class helloClass = InMemoryJavaComstackr.comstack("org.mdkt.HelloClass", sourceCode.toSsortingng()); 

Je pense que cela pourrait vous aider à comprendre comment comstackr une source Java à partir de la mémoire (la chaîne se trouve dans la classe).

Il utilise PrinterWriter et SsortingngWriter pour écrire la source dans une Ssortingng / en mémoire, puis utilise la classe JavaComstackr (depuis JDK 6) pour comstackr et exécuter le programme:

 import javax.tools.Diagnostic; import javax.tools.DiagnosticCollector; import javax.tools.JavaComstackr; import javax.tools.JavaComstackr.CompilationTask; import javax.tools.JavaFileObject; import javax.tools.SimpleJavaFileObject; import javax.tools.ToolProvider; import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.io.SsortingngWriter; import java.lang.reflect.InvocationTargetException; import java.net.URI; import java.net.URL; import java.net.URLClassLoader; import java.util.Arrays; public class ComstackSourceInMemory { public static void main(Ssortingng args[]) throws IOException { JavaComstackr comstackr = ToolProvider.getSystemJavaComstackr(); DiagnosticCollector diagnostics = new DiagnosticCollector(); SsortingngWriter writer = new SsortingngWriter(); PrintWriter out = new PrintWriter(writer); out.println("public class HelloWorld {"); out.println(" public static void main(Ssortingng args[]) {"); out.println(" System.out.println(\"This is in another java file\");"); out.println(" }"); out.println("}"); out.close(); JavaFileObject file = new JavaSourceFromSsortingng("HelloWorld", writer.toSsortingng()); Iterable compilationUnits = Arrays.asList(file); CompilationTask task = comstackr.getTask(null, null, diagnostics, null, null, compilationUnits); boolean success = task.call(); for (Diagnostic diagnostic : diagnostics.getDiagnostics()) { System.out.println(diagnostic.getCode()); System.out.println(diagnostic.getKind()); System.out.println(diagnostic.getPosition()); System.out.println(diagnostic.getStartPosition()); System.out.println(diagnostic.getEndPosition()); System.out.println(diagnostic.getSource()); System.out.println(diagnostic.getMessage(null)); } System.out.println("Success: " + success); if (success) { try { URLClassLoader classLoader = URLClassLoader.newInstance(new URL[] { new File("").toURI().toURL() }); Class.forName("HelloWorld", true, classLoader).getDeclaredMethod("main", new Class[] { Ssortingng[].class }).invoke(null, new Object[] { null }); } catch (ClassNotFoundException e) { System.err.println("Class not found: " + e); } catch (NoSuchMethodException e) { System.err.println("No such method: " + e); } catch (IllegalAccessException e) { System.err.println("Illegal access: " + e); } catch (InvocationTargetException e) { System.err.println("Invocation target: " + e); } } } } class JavaSourceFromSsortingng extends SimpleJavaFileObject { final Ssortingng code; JavaSourceFromSsortingng(Ssortingng name, Ssortingng code) { super(URI.create("ssortingng:///" + name.replace('.','/') + Kind.SOURCE.extension),Kind.SOURCE); this.code = code; } @Override public CharSequence getCharContent(boolean ignoreEncodingErrors) { return code; } } 

Si vous regardez le lien de référence, vous trouverez également quelques autres exemples

Référence:

  • Comstackr à partir de la mémoire

C’est une classe qui comstack entièrement en mémoire.

J’ai pris (presque) l’intégralité de ceci depuis http://javapracs.blogspot.de/2011/06/dynamic-in-memory-compilation-using.html par Rekha Kumari (juin 2011). Bien que cette version soit plus de 100 lignes plus courte et possède plus de fonctionnalités (mais pas de documents: P).

EDIT: Depuis que je viens de recevoir 2 votes positifs, je veux redonner et éditer ma nouvelle version dans: Il comstack plusieurs classes à la fois, le seul moyen de comstackr des classes qui dépendent les unes des autres. Si vous vous posez des questions sur la classe “ComstackrFeedback”: Je fais actuellement un petit IDE Java pour les jeux de codage là où j’en avais besoin. Je l’inclus ici parce que je suppose que vous voulez faire quelque chose, et la prédigestion pourrait vous aider. EDIT: Et je me rends compte qu’une partie du code dans la classe ComstackrFeedback est une merde complète. J’ai commencé avec le projet très récemment, mais cette classe que j’ai recyclée à partir d’une tentative vieille de plusieurs années.

EDIT: Bonjour, un autre vote upvote! Ajouter une méthode qui dérive le nom complet de la classe du code source d’une classe (y compris le nom du package, s’il est fourni). Très utile pour appeler le compilateur, qui a besoin de cette information.

EDIT: Ajout d’une méthode MISSING à la méthode qui détermine le nom complet de la classe. (Pardon)

DEMO CLASS:

 import java.util.ArrayList; import java.util.List; public class Demo { public static void main(final Ssortingng[] args) { final InMemoryComstackr.IMCSourceCode cls1source; final InMemoryComstackr.IMCSourceCode cls2source; final SsortingngBuilder sb = new SsortingngBuilder(); sb.append("package toast;\n"); sb.append("public class DynaClass {\n"); sb.append(" public static void main(final Ssortingng[] args) {"); sb.append(" System.out.println(\"Based massively on the work of Rekha Kumari, http://javapracs.blogspot.de/2011/06/dynamic-in-memory-compilation-using.html\");\n"); sb.append(" System.out.println(\"This is the main method speaking.\");\n"); sb.append(" System.out.println(\"Args: \" + java.util.Arrays.toSsortingng(args));\n"); sb.append(" final Test test = new Test();\n"); sb.append(" }\n"); sb.append(" public Ssortingng toSsortingng() {\n"); sb.append(" return \"Hello, I am \" + "); sb.append("this.getClass().getSimpleName();\n"); sb.append(" }\n"); sb.append("}\n"); cls1source = new InMemoryComstackr.IMCSourceCode("toast.DynaClass", sb.toSsortingng()); sb.setLength(0); sb.append("package toast;\n"); sb.append("public class Test {\n"); sb.append(" public Test() {\n"); sb.append(" System.out.println(\"class Test constructor reporting in.\");\n"); sb.append(" System.out.println(new DynaClass());\n"); sb.append(" }\n"); sb.append("}\n"); cls2source = new InMemoryComstackr.IMCSourceCode("toast.Test", sb.toSsortingng()); final List classSources = new ArrayList<>(); classSources.add(cls1source); classSources.add(cls2source); final InMemoryCompiler uCompiler = new InMemoryCompiler(classSources); final CompilerFeedback compilerFeedback = uCompiler.compile(); System.out.println("\n\nCOMPILER FEEDBACK: " + compilerFeedback); if (compilerFeedback != null && compilerFeedback.success) { try { System.out.println("\nTOSTRING DEMO:"); uCompiler.runToString(cls1source.fullClassName); } catch (Exception e) { e.printStackTrace(); } try { System.out.println("\nMAIN DEMO:"); uCompiler.runMain(cls1source.fullClassName, new String[] { "test1", "test2" }); } catch (Exception e) { e.printStackTrace(); } } System.exit(0); } } 

COMPILER CLASS:

 import javax.tools.*; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URI; import java.security.SecureClassLoader; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * MASSIVELY based on http://javapracs.blogspot.de/2011/06/dynamic-in-memory-compilation-using.html by Rekha Kumari * (June 2011) */ final public class InMemoryComstackr { final public static class IMCSourceCode { final public Ssortingng fullClassName; final public Ssortingng sourceCode; /** * @param fullClassName Full name of the class that will be comstackd. If the class should be in some package, * fullName should contain it too, for example: "testpackage.DynaClass" * @param sourceCode the source code */ public IMCSourceCode(final Ssortingng fullClassName, final Ssortingng sourceCode) { this.fullClassName = fullClassName; this.sourceCode = sourceCode; } } final public boolean valid; final private List classSourceCodes; final private JavaFileManager fileManager; public InMemoryComstackr(final List classSourceCodes) { this.classSourceCodes = classSourceCodes; final JavaComstackr comstackr = ToolProvider.getSystemJavaComstackr(); if (comstackr == null) { fileManager = null; valid = false; System.err.println("ToolProvider.getSystemJavaComstackr() returned null! This program needs to be run on a system with an installed JDK."); return; } valid = true; fileManager = new ForwardingJavaFileManager(comstackr.getStandardFileManager(null, null, null)) { final private Map byteStreams = new HashMap<>(); @Override public ClassLoader getClassLoader(final Location location) { return new SecureClassLoader() { @Override protected Class findClass(final Ssortingng className) throws ClassNotFoundException { final ByteArrayOutputStream bos = byteStreams.get(className); if (bos == null) { return null; } final byte[] b = bos.toByteArray(); return super.defineClass(className, b, 0, b.length); } }; } @Override public JavaFileObject getJavaFileForOutput(final Location location, final Ssortingng className, final JavaFileObject.Kind kind, final FileObject sibling) throws IOException { return new SimpleJavaFileObject(URI.create("ssortingng:///" + className.replace('.', '/') + kind.extension), kind) { @Override public OutputStream openOutputStream() throws IOException { ByteArrayOutputStream bos = byteStreams.get(className); if (bos == null) { bos = new ByteArrayOutputStream(); byteStreams.put(className, bos); } return bos; } }; } }; } public ComstackrFeedback comstack() { if (!valid) { return null; } final List files = new ArrayList<>(); for (IMCSourceCode classSourceCode : classSourceCodes) { URI uri = null; try { uri = URI.create("string:///" + classSourceCode.fullClassName.replace('.', '/') + JavaFileObject.Kind.SOURCE.extension); } catch (Exception e) { // e.printStackTrace(); } if (uri != null) { final SimpleJavaFileObject sjfo = new SimpleJavaFileObject(uri, JavaFileObject.Kind.SOURCE) { @Override public CharSequence getCharContent(final boolean ignoreEncodingErrors) { return classSourceCode.sourceCode; } }; files.add(sjfo); } } final DiagnosticCollector diagnostics = new DiagnosticCollector<>(); final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); if (files.size() > 0) { final JavaComstackr.CompilationTask task = comstackr.getTask(null, fileManager, diagnostics, null, null, files); return new ComstackrFeedback(task.call(), diagnostics); } else { return null; } } public void runToSsortingng(final Ssortingng className) throws InstantiationException, IllegalAccessException, ClassNotFoundException { if (!valid) { return; } final Class theClass = getComstackdClass(className); final Object instance = theClass.newInstance(); System.out.println(instance); } public void runMain(final Ssortingng className, final Ssortingng[] args) throws IllegalAccessException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException { if (!valid) { return; } final Class theClass = getComstackdClass(className); final Method mainMethod = theClass.getDeclaredMethod("main", Ssortingng[].class); mainMethod.invoke(null, new Object[] { args }); } public Class getComstackdClass(final Ssortingng className) throws ClassNotFoundException { if (!valid) { throw new IllegalStateException("InMemoryComstackr instance not usable because ToolProvider.getSystemJavaComstackr() returned null: No JDK installed."); } final ClassLoader classLoader = fileManager.getClassLoader(null); final Class ret = classLoader.loadClass(className); if (ret == null) { throw new ClassNotFoundException("Class returned by ClassLoader was null!"); } return ret; } } 

COMPILERFEEDBACK CLASS:

 import javax.tools.Diagnostic; import javax.tools.DiagnosticCollector; import javax.tools.JavaFileObject; import javax.tools.SimpleJavaFileObject; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Locale; final public class ComstackrFeedback { final public boolean success; final public List messages = new ArrayList<>(); public CompilerFeedback(final Boolean success, final DiagnosticCollector diagnostics) { this.success = success != null && success; for (Diagnostic diagnostic : diagnostics.getDiagnostics()) { messages.add(new ComstackrMessage(diagnostic)); } } public Ssortingng toSsortingng() { final SsortingngBuilder sb = new SsortingngBuilder(); sb.append("SUCCESS: ").append(success).append('\n'); final int iTop = messages.size(); for (int i = 0; i < iTop; i++) { sb.append("\n[MESSAGE ").append(i + 1).append(" OF ").append(iTop).append("]\n\n"); // sb.append(messages.get(i).toString()).append("\n"); // sb.append(messages.get(i).toStringForList()).append("\n"); sb.append(messages.get(i).toStringForDebugging()).append("\n"); } return sb.toString(); } final public static class CompilerMessage { final public Diagnostic comstackrInfo; final public Ssortingng typeOfProblem; final public Ssortingng typeOfProblem_forDebugging; final public Ssortingng multiLineMessage; final public int lineNumber; final public int columnNumber; final public int textHighlightPos_lineStart; final public int textHighlightPos_problemStart; final public int textHighlightPos_problemEnd; final public Ssortingng sourceCode; final public Ssortingng codeOfConcern; final public Ssortingng codeOfConcernLong; ComstackrMessage(final Diagnostic diagnostic) { final JavaFileObject sourceFileObject = diagnostic.getSource(); Ssortingng sourceCodePreliminary = null; if (sourceFileObject instanceof SimpleJavaFileObject) { final SimpleJavaFileObject simpleSourceFileObject = (SimpleJavaFileObject) sourceFileObject; try { final CharSequence charSequence = simpleSourceFileObject.getCharContent(false); sourceCodePreliminary = charSequence.toSsortingng(); } catch (IOException e) { e.printStackTrace(); } } if (sourceCodePreliminary == null) { sourceCode = "[SOURCE CODE UNAVAILABLE]"; } else { sourceCode = sourceCodePreliminary; } comstackrInfo = diagnostic; typeOfProblem = diagnostic.getKind().name(); typeOfProblem_forDebugging = "toSsortingng() = " + diagnostic.getKind().toSsortingng() + "; name() = " + typeOfProblem; lineNumber = (int) comstackrInfo.getLineNumber(); columnNumber = (int) comstackrInfo.getColumnNumber(); final int sourceLen = sourceCode.length(); textHighlightPos_lineStart = (int) Math.min(Math.max(0, diagnostic.getStartPosition()), sourceLen); textHighlightPos_problemStart = (int) Math.min(Math.max(0, diagnostic.getPosition()), sourceLen); textHighlightPos_problemEnd = (int) Math.min(Math.max(0, diagnostic.getEndPosition()), sourceLen); final SsortingngBuilder reformattedMessage = new SsortingngBuilder(); final Ssortingng message = diagnostic.getMessage(Locale.US); final int messageCutOffPosition = message.indexOf("location:"); final Ssortingng[] messageParts; if (messageCutOffPosition >= 0) { messageParts = message.subssortingng(0, messageCutOffPosition).split("\n"); } else { messageParts = message.split("\n"); } for (Ssortingng s : messageParts) { Ssortingng s2 = s.sortingm(); if (s2.length() > 0) { boolean lengthChanged; do { final int lBeforeReplace = s2.length(); s2 = s2.replace(" ", " "); lengthChanged = (s2.length() != lBeforeReplace); } while (lengthChanged); reformattedMessage.append(s2).append("\n"); } } codeOfConcern = sourceCode.subssortingng(textHighlightPos_problemStart, textHighlightPos_problemEnd); codeOfConcernLong = sourceCode.subssortingng(textHighlightPos_lineStart, textHighlightPos_problemEnd); if (!codeOfConcern.isEmpty()) { reformattedMessage.append("Code of concern: \"").append(codeOfConcern).append('\"'); } multiLineMessage = reformattedMessage.toSsortingng(); } public Ssortingng toSsortingngForList() { if (comstackrInfo == null) { return "No comstackr!"; } else { return comstackrInfo.getCode(); } } public Ssortingng toSsortingngForDebugging() { final SsortingngBuilder ret = new SsortingngBuilder(); ret.append("Type of problem: ").append(typeOfProblem_forDebugging).append("\n\n"); ret.append("Message:\n").append(multiLineMessage).append("\n\n"); ret.append(comstackrInfo.getCode()).append("\n\n"); ret.append("line number: ").append(lineNumber).append("\n"); ret.append("column number: ").append(columnNumber).append("\n"); ret.append("textHighlightPos_lineStart: ").append(textHighlightPos_lineStart).append("\n"); ret.append("textHighlightPos_problemStart: ").append(textHighlightPos_problemStart).append("\n"); ret.append("textHighlightPos_problemEnd: ").append(textHighlightPos_problemEnd).append("\n"); return ret.toSsortingng(); } @Override public Ssortingng toSsortingng() { // return comstackrInfo.getMessage(Locale.US); return typeOfProblem + ": " + multiLineMessage + "\n"; } } } 

MÉTHODE UTILITAIRE (Pas nécessaire pour les trois classes plus haut):

 final public static Ssortingng PREFIX_CLASSNAME = "class "; final public static Ssortingng PREFIX_PACKAGENAME = "package "; final public static Ssortingng CHARSET_JAVAKEYWORDENDERS = " \n[](){}<>;,\"\\/*+-=%!&?@:"; /** * @return eg "com.dreamspacepresident.TestClass" if the source's first root level "class" (I'm talking about {} * hierarchy.) is named "TestClass", and if the "package" name is "com.dreamspacepresident". Null is returned if * sourceCode is null or does not provide a class name. (Mind that the parsing is done in a quite crappy way.) */ public static String deriveFullClassNameFromSource(final String sourceCode) { if (sourceCode == null) { return null; } final int firstBr = sourceCode.indexOf('{'); if (firstBr >= 0) { // DETERMINE CLASS NAME final int firstClass = sourceCode.indexOf(PREFIX_CLASSNAME); if (firstClass < firstBr) { String className = sourceCode.substring(firstClass + PREFIX_CLASSNAME.length(), firstBr).trim(); final int classNameEnd = indexOfAnyOfThese(className, CHARSET_JAVAKEYWORDENDERS); if (classNameEnd >= 0) { className = className.subssortingng(0, classNameEnd); } if (!className.isEmpty()) { // DETERMINE PACKAGE NAME Ssortingng packageName = null; final int firstPackage = sourceCode.indexOf(PREFIX_PACKAGENAME); if (firstPackage >= 0 && firstPackage < firstBr && firstPackage < firstClass) { packageName = sourceCode.substring(firstPackage + PREFIX_PACKAGENAME.length(), firstBr).trim(); final int packageNameEnd = indexOfAnyOfThese(packageName, CHARSET_JAVAKEYWORDENDERS); if (packageNameEnd >= 0) { packageName = packageName.subssortingng(0, packageNameEnd); } } return (packageName != null && !packageName.isEmpty() ? packageName + "." : "") + className; } } } return null; } /** * Looks for the first occurrence of ANY of the given characters, which is easier than using a bunch of * Ssortingng.indexOf() calls. * * @return -1 if not found, otherwise the Ssortingng index of the first hit */ public static int indexOfAnyOfThese(final Ssortingng text, final Ssortingng characters) { if (text != null && !text.isEmpty() && characters != null && !characters.isEmpty()) { final int lenT = text.length(); final int lenC = characters.length(); for (int i = 0; i < lenT; i++) { final char c = text.charAt(i); for (int ii = 0; ii < lenC; ii++) { if (c == characters.charAt(ii)) { return i; } } } } return -1; } 

J’ai écrit une bibliothèque pour le faire il y a quelques années. Il prend une chaîne qui peut contenir des classes nestedes, les comstack et les charge éventuellement dans le chargeur de classe actuel (vous n’avez donc pas besoin d’un chargeur de classe supplémentaire) Si la machine virtuelle s’exécute en mode débogage, elle écrit le code généré dans un fichier vous pouvez donc parcourir votre code généré.

http://vanillajava.blogspot.co.uk/2010_11_01_archive.html


Pour paraphraser l’exemple d’ erolagnab vous pouvez faire

 SsortingngBuilder sourceCode = new SsortingngBuilder(); sourceCode.append("package org.mdkt;\n") .append("public class HelloClass {\n") .append(" public Ssortingng hello() { return \"hello\"; }") .append("}"); Class helloClass = CACHED_COMPILER.comstack("org.mdkt.HelloClass", sourceCode.toSsortingng()); 

Mise à jour, la source est disponible ici https://github.com/OpenHFT/Java-Runtime-Comstackr

Et vous pouvez obtenir la dernière version via maven http://search.maven.org/#browse%7C842970587


Un exemple plus long.

 // this writes the file to disk only when debugging is enabled. CachedComstackr cc = ComstackrUtils.DEBUGGING ? new CachedComstackr(new File(parent, "src/test/java"), new File(parent, "target/comstackd")) : ComstackrUtils.CACHED_COMPILER; Ssortingng text = "generated test " + new Date(); Class fooBarTeeClass = cc.loadFromJava("eg.FooBarTee", "package eg;\n" + '\n' + "import eg.components.BarImpl;\n" + "import eg.components.TeeImpl;\n" + "import eg.components.Foo;\n" + '\n' + "public class FooBarTee{\n" + " public final Ssortingng name;\n" + " public final TeeImpl tee;\n" + " public final BarImpl bar;\n" + " public final BarImpl copy;\n" + " public final Foo foo;\n" + '\n' + " public FooBarTee(Ssortingng name) {\n" + " // when viewing this file, ensure it is synchronised with the copy on disk.\n" + " System.out.println(\"" + text + "\");\n" + " this.name = name;\n" + '\n' + " tee = new TeeImpl(\"test\");\n" + '\n' + " bar = new BarImpl(tee, 55);\n" + '\n' + " copy = new BarImpl(tee, 555);\n" + '\n' + " // you should see the current date here after synchronisation.\n" + " foo = new Foo(bar, copy, \"" + text + "\", 5);\n" + " }\n" + '\n' + " public void start() {\n" + " }\n" + '\n' + " public void stop() {\n" + " }\n" + '\n' + " public void close() {\n" + " stop();\n" + '\n' + " }\n" + "}\n"); // add a debug break point here and step into this method. FooBarTee fooBarTee = new FooBarTee("test foo bar tee"); Foo foo = fooBarTee.foo; assertNotNull(foo); assertEquals(text, foo.s); 

J’ai voulu:

  • compilation en mémoire d’un fichier java (utile pour Java en tant que langage de script)
  • Pas de dépendances supplémentaires (facile à configurer)
  • Mise en œuvre en un nombre de fichiers aussi réduit que possible (facile à intégrer dans un projet)

Vous pouvez l’essayer d’abord ici: http://ideone.com/cu1GhE#view_edit_box

Le code suivant est basé sur le code Rekha Kumari :

Main.java

 package com.mycompany.java; //import org.slf4j.Logger; //import org.slf4j.LoggerFactory; import java.io.PrintWriter; import java.io.SsortingngWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class Main { //private static final Logger logger = LoggerFactory.getLogger(Main.class); public static void main(Ssortingng[] args) { try { SsortingngWriter writer = new SsortingngWriter(); PrintWriter out = new PrintWriter(writer); out.println("package com.mycompany.script;"); out.println(""); out.println("public class HelloWorld {"); out.println(" public static void main(Ssortingng args[]) {"); out.println(" System.out.println(\"This is in another java file\");"); out.println(" }"); out.println("}"); out.close(); Ssortingng fullName = "com.mycompany.script.HelloWorld"; Ssortingng src = writer.toSsortingng(); DynamicComstackr uComstackr = new DynamicComstackr(fullName, src); uComstackr.comstack(); uComstackr.run(); } catch (Exception e) { //logger.error("Exception:", e); System.out.print("Exception"); } } } 

DynamicComstackr.java

 package com.mycompany.java; //import org.slf4j.Logger; //import org.slf4j.LoggerFactory; import javax.tools.*; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.lang.reflect.InvocationTargetException; import java.net.URI; import java.security.SecureClassLoader; import java.util.ArrayList; import java.util.List; // Based on: http://javapracs.blogspot.cz/2011/06/dynamic-in-memory-compilation-using.html public class DynamicComstackr { //private static final Logger logger = LoggerFactory.getLogger(DynamicComstackr.class); private JavaFileManager fileManager; private Ssortingng fullName; private Ssortingng sourceCode; public DynamicComstackr(Ssortingng fullName, Ssortingng srcCode) { this.fullName = fullName; this.sourceCode = srcCode; this.fileManager = initFileManager(); } public JavaFileManager initFileManager() { if (fileManager != null) return fileManager; else { JavaComstackr comstackr = ToolProvider.getSystemJavaComstackr(); fileManager = new ClassFileManager(comstackr .getStandardFileManager(null, null, null)); return fileManager; } } public void comstack() { JavaComstackr comstackr = ToolProvider.getSystemJavaComstackr(); List files = new ArrayList<>(); files.add(new CharSequenceJavaFileObject(fullName, sourceCode)); compiler.getTask( null, fileManager, null, null, null, files ).call(); } public void run() throws InstantiationException, IllegalAccessException, ClassNotFoundException { try { fileManager .getClassLoader(null) .loadClass(fullName) .getDeclaredMethod("main", new Class[]{String[].class}) .invoke(null, new Object[]{null}); } catch (InvocationTargetException e) { System.out.print("InvocationTargetException"); //logger.error("InvocationTargetException:", e); } catch (NoSuchMethodException e) { System.out.print("NoSuchMethodException "); //logger.error("NoSuchMethodException:", e); } } public class CharSequenceJavaFileObject extends SimpleJavaFileObject { /** * CharSequence representing the source code to be compiled */ private CharSequence content; public CharSequenceJavaFileObject(String className, CharSequence content) { super(URI.create("string:///" + className.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE); this.content = content; } public CharSequence getCharContent(boolean ignoreEncodingErrors) { return content; } } public class ClassFileManager extends ForwardingJavaFileManager { private JavaClassObject javaClassObject; public ClassFileManager(StandardJavaFileManager standardManager) { super(standardManager); } @Override public ClassLoader getClassLoader(Location location) { return new SecureClassLoader() { @Override protected Class findClass(Ssortingng name) throws ClassNotFoundException { byte[] b = javaClassObject.getBytes(); return super.defineClass(name, javaClassObject.getBytes(), 0, b.length); } }; } public JavaFileObject getJavaFileForOutput(Location location, Ssortingng className, JavaFileObject.Kind kind, FileObject sibling) throws IOException { this.javaClassObject = new JavaClassObject(className, kind); return this.javaClassObject; } } public class JavaClassObject extends SimpleJavaFileObject { protected final ByteArrayOutputStream bos = new ByteArrayOutputStream(); public JavaClassObject(Ssortingng name, Kind kind) { super(URI.create("ssortingng:///" + name.replace('.', '/') + kind.extension), kind); } public byte[] getBytes() { return bos.toByteArray(); } @Override public OutputStream openOutputStream() throws IOException { return bos; } } } 

Je voudrais présenter ma solution qui fonctionne bien en production.

Voici les trois fichiers de code source.

MemoryJavaComstackr.java

 package me.soulmachine.comstackr; import java.io.IOException; import java.io.PrintWriter; import java.io.Writer; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import java.util.Map; import javax.tools.*; /** * Simple interface to Java comstackr using JSR 199 Comstackr API. */ public class MemoryJavaComstackr { private javax.tools.JavaComstackr tool; private StandardJavaFileManager stdManager; public MemoryJavaComstackr() { tool = ToolProvider.getSystemJavaComstackr(); if (tool == null) { throw new RuntimeException("Could not get Java comstackr. Please, ensure that JDK is used instead of JRE."); } stdManager = tool.getStandardFileManager(null, null, null); } /** * Comstack a single static method. */ public Method comstackStaticMethod(final Ssortingng methodName, final Ssortingng className, final Ssortingng source) throws ClassNotFoundException { final Map classBytes = comstack(className + ".java", source); final MemoryClassLoader classLoader = new MemoryClassLoader(classBytes); final Class clazz = classLoader.loadClass(className); final Method[] methods = clazz.getDeclaredMethods(); for (final Method method : methods) { if (method.getName().equals(methodName)) { if (!method.isAccessible()) method.setAccessible(true); return method; } } throw new NoSuchMethodError(methodName); } public Map comstack(Ssortingng fileName, Ssortingng source) { return comstack(fileName, source, new PrintWriter(System.err), null, null); } /** * comstack given Ssortingng source and return bytecodes as a Map. * * @param fileName source fileName to be used for error messages etc. * @param source Java source as Ssortingng * @param err error writer where diagnostic messages are written * @param sourcePath location of additional .java source files * @param classPath location of additional .class files */ private Map comstack(Ssortingng fileName, Ssortingng source, Writer err, Ssortingng sourcePath, Ssortingng classPath) { // to collect errors, warnings etc. DiagnosticCollector diagnostics = new DiagnosticCollector(); // create a new memory JavaFileManager MemoryJavaFileManager fileManager = new MemoryJavaFileManager(stdManager); // prepare the compilation unit List compUnits = new ArrayList(1); compUnits.add(fileManager.makeSsortingngSource(fileName, source)); return comstack(compUnits, fileManager, err, sourcePath, classPath); } private Map comstack(final List compUnits, final MemoryJavaFileManager fileManager, Writer err, Ssortingng sourcePath, Ssortingng classPath) { // to collect errors, warnings etc. DiagnosticCollector diagnostics = new DiagnosticCollector(); // javac options List options = new ArrayList(); options.add("-Xlint:all"); // options.add("-g:none"); options.add("-deprecation"); if (sourcePath != null) { options.add("-sourcepath"); options.add(sourcePath); } if (classPath != null) { options.add("-classpath"); options.add(classPath); } // create a compilation task javax.tools.JavaComstackr.CompilationTask task = tool.getTask(err, fileManager, diagnostics, options, null, compUnits); if (task.call() == false) { PrintWriter perr = new PrintWriter(err); for (Diagnostic diagnostic : diagnostics.getDiagnostics()) { perr.println(diagnostic); } perr.flush(); return null; } Map classBytes = fileManager.getClassBytes(); try { fileManager.close(); } catch (IOException exp) { } return classBytes; } } 

MemoryJavaFileManager.java

 package me.soulmachine.comstackr; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FilterOutputStream; import java.io.IOException; import java.io.OutputStream; import java.net.URI; import java.nio.CharBuffer; import java.util.HashMap; import java.util.Map; import javax.tools.FileObject; import javax.tools.ForwardingJavaFileManager; import javax.tools.JavaFileManager; import javax.tools.JavaFileObject; import javax.tools.JavaFileObject.Kind; import javax.tools.SimpleJavaFileObject; /** * JavaFileManager that keeps comstackd .class bytes in memory. */ @SuppressWarnings("unchecked") final class MemoryJavaFileManager extends ForwardingJavaFileManager { /** Java source file extension. */ private final static Ssortingng EXT = ".java"; private Map classBytes; public MemoryJavaFileManager(JavaFileManager fileManager) { super(fileManager); classBytes = new HashMap<>(); } public Map getClassBytes() { return classBytes; } public void close() throws IOException { classBytes = null; } public void flush() throws IOException { } /** * A file object used to represent Java source coming from a ssortingng. */ private static class SsortingngInputBuffer extends SimpleJavaFileObject { final Ssortingng code; SsortingngInputBuffer(Ssortingng fileName, Ssortingng code) { super(toURI(fileName), Kind.SOURCE); this.code = code; } public CharBuffer getCharContent(boolean ignoreEncodingErrors) { return CharBuffer.wrap(code); } } /** * A file object that stores Java bytecode into the classBytes map. */ private class ClassOutputBuffer extends SimpleJavaFileObject { private Ssortingng name; ClassOutputBuffer(Ssortingng name) { super(toURI(name), Kind.CLASS); this.name = name; } public OutputStream openOutputStream() { return new FilterOutputStream(new ByteArrayOutputStream()) { public void close() throws IOException { out.close(); ByteArrayOutputStream bos = (ByteArrayOutputStream)out; classBytes.put(name, bos.toByteArray()); } }; } } public JavaFileObject getJavaFileForOutput(JavaFileManager.Location location, Ssortingng className, Kind kind, FileObject sibling) throws IOException { if (kind == Kind.CLASS) { return new ClassOutputBuffer(className); } else { return super.getJavaFileForOutput(location, className, kind, sibling); } } static JavaFileObject makeSsortingngSource(Ssortingng fileName, Ssortingng code) { return new SsortingngInputBuffer(fileName, code); } static URI toURI(Ssortingng name) { File file = new File(name); if (file.exists()) { return file.toURI(); } else { try { final SsortingngBuilder newUri = new SsortingngBuilder(); newUri.append("mfm:///"); newUri.append(name.replace('.', '/')); if(name.endsWith(EXT)) newUri.replace(newUri.length() - EXT.length(), newUri.length(), EXT); return URI.create(newUri.toSsortingng()); } catch (Exception exp) { return URI.create("mfm:///com/sun/script/java/java_source"); } } } } 

MemoryClassLoader.java

 package me.soulmachine.comstackr; import java.io.File; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.SsortingngTokenizer; /** * ClassLoader that loads .class bytes from memory. */ final class MemoryClassLoader extends URLClassLoader { private Map classBytes; public MemoryClassLoader(Map classBytes, Ssortingng classPath, ClassLoader parent) { super(toURLs(classPath), parent); this.classBytes = classBytes; } public MemoryClassLoader(Map classBytes, Ssortingng classPath) { this(classBytes, classPath, ClassLoader.getSystemClassLoader()); } public MemoryClassLoader(Map classBytes) { this(classBytes, null, ClassLoader.getSystemClassLoader()); } public Class load(Ssortingng className) throws ClassNotFoundException { return loadClass(className); } public Iterable loadAll() throws ClassNotFoundException { List classes = new ArrayList(classBytes.size()); for (Ssortingng name : classBytes.keySet()) { classes.add(loadClass(name)); } return classes; } protected Class findClass(Ssortingng className) throws ClassNotFoundException { byte[] buf = classBytes.get(className); if (buf != null) { // clear the bytes in map -- we don't need it anymore classBytes.put(className, null); return defineClass(className, buf, 0, buf.length); } else { return super.findClass(className); } } private static URL[] toURLs(Ssortingng classPath) { if (classPath == null) { return new URL[0]; } List list = new ArrayList(); SsortingngTokenizer st = new SsortingngTokenizer(classPath, File.pathSeparator); while (st.hasMoreTokens()) { Ssortingng token = st.nextToken(); File file = new File(token); if (file.exists()) { try { list.add(file.toURI().toURL()); } catch (MalformedURLException mue) {} } else { try { list.add(new URL(token)); } catch (MalformedURLException mue) {} } } URL[] res = new URL[list.size()]; list.toArray(res); return res; } } 

Explanations :

  1. In order to represent a Java source file in memory instead of disk, I defined a SsortingngInputBuffer class in the MemoryJavaFileManager.java .
  2. To save the comstackd .class files in memory, I implemented a class MemoryJavaFileManager . The main idea is to override the function getJavaFileForOutput() to store bytecodes into a map.
  3. To load the bytecodes in memory, I have to implement a customized classloader MemoryClassLoader , which reads bytecodes in the map and turn them into classes.

Here is a unite test.

 package me.soulmachine.comstackr; import org.junit.Test; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import static org.junit.Assert.assertEquals; public class MemoryJavaComstackrTest { private final static MemoryJavaComstackr comstackr = new MemoryJavaComstackr(); @Test public void comstackStaticMethodTest() throws ClassNotFoundException, InvocationTargetException, IllegalAccessException { final Ssortingng source = "public final class Solution {\n" + "public static Ssortingng greeting(Ssortingng name) {\n" + "\treturn \"Hello \" + name;\n" + "}\n}\n"; final Method greeting = comstackr.comstackStaticMethod("greeting", "Solution", source); final Object result = greeting.invoke(null, "soulmachine"); assertEquals("Hello soulmachine", result.toSsortingng()); } } 

Référence

  1. JavaComstackr.java from Cloudera Morphlines
  2. How to create an object from a ssortingng in Java (how to eval a ssortingng)?
  3. InMemoryJavaComstackr
  4. Java-Runtime-Comstackr
  5. [动态的Java – 无废话JavaComstackrAPI中文指南]
  6. Comstack and Run Java Source Code in Memory .
 Ssortingng fileToComstack = ; JavaComstack comstackr = ToolProvider.getSystemJavaComstackr(); if( comstackr.run(null, null, null, "PACKAGE_NAME" + java.io.File.separator +"CLASS_NAME.java") == 0 ) System.out.println("Compilation is successful"); else System.out.println("Compilation Failed");