'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]

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