1

I'm not an expert in Java and I'm pretty new to the whole concept of compiling and running dynamic generated code, which is so simple in other languages, expecially script languages like Javascript and PHP.

I'm following this snippet of code: http://www.java2s.com/Code/Java/JDK-6/CompilingfromMemory.htm and I made something like this:

private final String = "GeneratedClass_" + Long.toHexString(random.nextLong());
private Method compileCode(String code) {
    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
    if (compiler == null) return null;

    DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();

    JavaFileObject source = new JavaSource(className, code);
    Iterable<? extends JavaFileObject> compilationUnits = Arrays.asList(source);
    CompilationTask task = compiler.getTask(null, null, diagnostics, null, null, compilationUnits);

    if (!task.call()) return null;
    try {
        return Class.forName(className).getDeclaredMethods()[0];
    } catch (ClassNotFoundException e) {}
    return null;
}

private class JavaSource extends SimpleJavaFileObject {
    final String code;
    JavaSource(String name, String code) {
        super(URI.create("string:///" + name.replace('.','/') + Kind.SOURCE.extension),Kind.SOURCE);
        this.code = code;
    }

    @Override
    public CharSequence getCharContent(boolean ignoreEncodingErrors) {return code;}
}

Just imagine that the string code is something like

"public class GeneratedClass_65ce701239c32ce0 {
    public String hello() {
        return "Hello, world!";
    }
}"

It works well until that Class.forName which throws a ClassNotFoundException. I'm puzzled since it doesn't seem I cut something important from the snippet: so, the class was compiled but where has it gone?

I read something about using a different class loader, but since, like I said, I'm pretty new to all this stuff I don't know where to head and how to use it, and how should I define my own extension of ClassLoader. The only thing I know is that everything seems quite complicated to me...

Using Eclipse Indigo in Windows 7 and JDK 1.7.

MaxArt
  • 22,200
  • 10
  • 82
  • 81
  • 5
    Compiling code dynamically in Java is a pretty advanced topic, and I'm surprised that you feel you need it while still being a beginner in Java. What are you actually trying to do? There might be a better way that doesn't involve compiling at runtime. – Greg Hewgill Oct 15 '11 at 22:47
  • Well actually I was trying to port a Javascript "class" that dynamically generates strings and more generally documents, and it manages to do it by dynamically generating a function that returns the string. It worked like a charm in Javascript and I successfully ported it in PHP, so I wanted to try to port it in Java too. I tried to imagine something different, but that would have meant something like... well, creating my own compiler... – MaxArt Oct 15 '11 at 23:07

1 Answers1

2

One important thing you cut was all the error output and diagnostic information. You'd never know if something went wrong. However, everything looks correct. Your problem is most likely just that you didn't send any options to the compiler, so it'll write the class file out to wherever it feels like (current working directory is the default, I believe), and that's probably not on your classpath, especially in an IDE. Try running it from the command line to prove to yourself it works. This should work:

mkdir tmp
javac -d tmp <path your main class .java file>
java -cp .;tmp <your main class name>

If you're not familiar with the command-line tools, the argument to javac has to be a file system path to the .java file, and the argument to java needs to be the .-separated, fully-qualifed class name, like com.foo.Main. Doing that should:

  1. Compile your class to the tmp directory.
  2. Write your dynamically-generated class to the current directory.
  3. Successfully load the newly compiled class from the current directory because it's on the classpath.
Ryan Stewart
  • 126,015
  • 21
  • 180
  • 199
  • I see you point and it was helping, but I fear it's more complicated than that because the project has dependecies from another project - the one that actually creates the code and call the compiler, BTW. I've noticed that the generated .class file is in the project main directory, while the main class is, of course, under /bin. I think I can find a way to retrieve it and load it with a `ClassLoader`. Correct me if I'm wrong. – MaxArt Oct 16 '11 at 17:45
  • Yes, creating another ClassLoader to load your class would be another way to do it, though you can still encounter classpath concerns if you don't create and/or use it correctly. The main thing is that you need to make sure you always know where your class files are and plan out how they'll be loaded. You can't just write stuff out and expect it to magically work. – Ryan Stewart Oct 16 '11 at 18:34