import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.tools.FileObject;
import javax.tools.ForwardingJavaFileManager;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.StandardLocation;
import javax.tools.ToolProvider;

public class Evaluator{
    public static void main(String[] args){
        new Evaluator().eval(
            "SayHello",
            "public class SayHello{public void speak(){System.out.println(\"Hello world\");}}",
            "speak"
        );
    }

    void eval(String className, String classCode, String methodName){
        Map<String, ByteArrayOutputStream> classCache = new HashMap<>();
        JavaCompiler                       compiler   = ToolProvider.getSystemJavaCompiler();

        if ( null == compiler )
            throw new RuntimeException("Could not get a compiler.");

        StandardJavaFileManager                            sfm  = compiler.getStandardFileManager(null, null, null);
        ForwardingJavaFileManager<StandardJavaFileManager> fjfm = new ForwardingJavaFileManager<StandardJavaFileManager>(sfm){
            @Override
            public JavaFileObject getJavaFileForOutput(Location location, String className, JavaFileObject.Kind kind, FileObject sibling)
                    throws IOException{
                if (StandardLocation.CLASS_OUTPUT == location && JavaFileObject.Kind.CLASS == kind)
                    return new SimpleJavaFileObject(URI.create("mem: