'Java: Load class from string
I know this has probably something to do with class loaders, however I couldn't find an example (it might be I'm google-ing for the wrong keywords.
I am trying to load a class (or a method) form a string. The string doesn't contain the name of a class, but the code for a class, e.g.
class MyClass implements IMath {
public int add(int x, int y) {
return x + y;
}
}
and then do something like this:
String s = "class MyClass implements IMath { public int add(int x, int y) { return x + y; }}";
IMath loadedClass = someThing.loadAndInitialize(string);
int result = loadedClass.add(5,6);
Now obviously, the someThing.loadAndInitialize(string) - part is the one I don't know how to achieve. Is this even possible? Or would it be easier to run JavaScripts and somehow "give" the variables / objects (like x and y)?
Thank you for any hints.
Solution 1:[1]
You can use Rhino and JavaScript in JDK 7. That might be a good way to do it.
invokedynamic is coming....
If you want to stick with Java, you need something to parse the source and turn it into byte code - something like cglib.
Solution 2:[2]
An example of loading a class from a String without creating temporary class files. It is a shortened version of toluju's answer to a similar question.
import java.io.*;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.Arrays;
import javax.tools.*;
import javax.tools.JavaFileObject.Kind;
@SuppressWarnings({ "unchecked", "boxing", "hiding", "rawtypes" })
public class MemoryClassLoader extends ClassLoader {
public static void main(String[] args) throws Exception {
String className = "test.MyClass";
String javaSource = "package test; public class MyClass { public static void test() { System.out.println(\"Hello World\"); } }";
// use a parent class loader that can resolve the classes referenced in the source
ClassLoader parentClassLoader = MemoryClassLoader.class.getClassLoader();
Class<?> clazz = new MemoryClassLoader(parentClassLoader).compileAndLoad(className, javaSource);
clazz.getMethod("test").invoke(null);
}
public MemoryClassLoader(ClassLoader parent) {
super(parent);
}
public Class<?> compileAndLoad(String className, String javaSource) throws Exception {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StringWriter errorWriter = new StringWriter();
ByteArrayOutputStream compiledBytesOutputStream = new ByteArrayOutputStream();
SimpleJavaFileObject sourceFile = new SimpleJavaFileObject(URI.create("file:///" + className.replace('.', '/') + ".java"), Kind.SOURCE) {
@Override
public CharSequence getCharContent(boolean ignoreEncErrors) {
return javaSource;
}
};
SimpleJavaFileObject classFile = new SimpleJavaFileObject(URI.create("file:///" + className.replace('.', '/') + ".class"), Kind.CLASS) {
@Override
public OutputStream openOutputStream() throws IOException {
return compiledBytesOutputStream;
}
};
ForwardingJavaFileManager fileManager = new ForwardingJavaFileManager(compiler.getStandardFileManager(null, null, null)) {
@Override
public JavaFileObject getJavaFileForOutput(JavaFileManager.Location location, String className, JavaFileObject.Kind kind, FileObject sibling) throws IOException {
return classFile;
}
};
// compile class
if (!compiler.getTask(errorWriter, fileManager, null, null, null, Arrays.asList(sourceFile)).call()) {
throw new Exception(errorWriter.toString());
}
// load class
byte[] bytes = compiledBytesOutputStream.toByteArray();
return super.defineClass(className, bytes, 0, bytes.length);
}
}
Solution 3:[3]
At first you need to compile your code, for example using compiler API: ( http://www.accordess.com/wpblog/an-overview-of-java-compilation-api-jsr-199/, http://docs.oracle.com/javase/6/docs/api/javax/tools/package-summary.html). And after it load compiled class with ClassLoader ( http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/ClassLoader.html )
Solution 4:[4]
You could compile it using JavaCompiler but I suggest you to use Groovy for this run-time class creation. It would be much easier.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | duffymo |
| Solution 2 | |
| Solution 3 | dbf |
| Solution 4 |
