/* package whatever; // don't place package name! */
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;
import java.io.PrintWriter;
import java.io.StringWriter;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
class Ideone
{
// private static final Logger logger = LoggerFactory.getLogger(Main.class);
{
try {
out.println("package com.mycompany.scripts;");
out.println("");
out.println("public class HelloWorld {");
out.println(" public static void main(String args[]) {");
out.println(" System.out.println(\"This is in another java file\");");
out.println(" }");
out.println("}");
out.close();
// Full name of the class that will be compiled.
// If class should be in some package,
// fullName should contain it too
// (ex. "testpackage.DynaClass")
String fullName
= "com.mycompany.scripts.HelloWorld";
// Here we get and specify the source code of the class to be compiled
String src
= writer.
toString();
DynamicCompiler uCompiler = new DynamicCompiler(fullName, src);
uCompiler.compile();
uCompiler.run();
// logger.error("Exception:", e);
System.
out.
print("Exception"); }
}
}
// Based on: http://j...content-available-to-author-only...t.cz/2011/06/dynamic-in-memory-compilation-using.html
class DynamicCompiler {
private JavaFileManager fileManager;
this.fullName = fullName;
this.sourceCode = srcCode;
this.fileManager = initFileManager();
}
public JavaFileManager initFileManager() {
if (fileManager != null)
return fileManager;
else {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
fileManager = new
ClassFileManager(compiler
.getStandardFileManager(null, null, null));
return fileManager;
}
}
public void compile() {
// We get an instance of JavaCompiler. Then
// we create a file manager
// (our custom implementation of it)
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
// Dynamic compiling requires specifying
// a list of "files" to compile. In our case
// this is a list containing one "file" which is in our case
// our own implementation (see details below)
List<JavaFileObject> files = new ArrayList<>();
files.add(new CharSequenceJavaFileObject(fullName, sourceCode));
// We specify a task to the compiler. Compiler should use our file
// manager and our list of "files".
// Then we run the compilation with call()
compiler.getTask(
null,
fileManager,
null,
null,
null,
files
).call();
}
// Creating an instance of our compiled class and
// running its toString() method
try {
fileManager
.getClassLoader(null)
.loadClass(fullName)
.
getDeclaredMethod("main",
new Class[]{String[].
class}) .
invoke(null,
new Object[]{null}); //logger.error("InvocationTargetException:", e);
System.
out.
print("InvocationTargetException"); //logger.error("NoSuchMethodException:", e);
System.
out.
print("NoSuchMethodException"); }
}
public class CharSequenceJavaFileObject extends SimpleJavaFileObject {
/**
* CharSequence representing the source code to be compiled
*/
private CharSequence content;
/**
* This constructor will store the source code in the
* internal "content" variable and register it as a
* source code, using a URI containing the class full name
*
* @param className name of the public class in the source code
* @param content source code to compile
*/
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);
}
/**
* Will be used by us to get the class loader for our
* compiled class. It creates an anonymous class
* extending the SecureClassLoader which uses the
* byte code created by the compiler and stored in
* the JavaClassObject, and returns the Class for it
*/
@Override
@Override
byte[] b = javaClassObject.getBytes();
return super.defineClass(name, javaClassObject.getBytes(), 0, b.length);
}
};
}
public JavaFileObject getJavaFileForOutput
(Location location,
String className, JavaFileObject.
Kind kind, FileObject sibling
) throws IOException { this.javaClassObject = new JavaClassObject(className, kind);
return this.javaClassObject;
}
}
public class JavaClassObject extends SimpleJavaFileObject {
/**
* Byte code created by the compiler will be stored in this
* ByteArrayOutputStream so that we can later get the
* byte array out of it
* and put it in the memory as an instance of our class.
*/
/**
* Registers the compiled class object under URI
* containing the class full name
*
* @param name
* Full name of the compiled class
* @param kind
* Kind of the data. It will be CLASS in our case
*/
public JavaClassObject
(String name, Kind kind
) { super(URI.create("string:///" + name.replace('.', '/')
+ kind.extension), kind);
}
/**
* Will be used by our file manager to get the byte code that
* can be put into memory to instantiate our class
*
* @return compiled byte code
*/
public byte[] getBytes() {
return bos.toByteArray();
}
/**
* Will provide the compiler with an output stream that leads
* to our byte array. This way the compiler will write everything
* into the byte array that we will instantiate later
*/
@Override
return bos;
}
}
}