In the following example, I'm trying to use sun.tools.javac.Main
to dynamically compile a class I generate, then instantiate an object of that class and invoke a method. So far, I can't even get passed loading the generated class. I get the following exception in Eclipse:
java.lang.ClassNotFoundException: TestHello_1289950330167
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClassInternal(Unknown Source)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Unknown Source)
at MyClassGenerator.runIt(MyClassGenerator.java:47)
at MyClassGenerator.main(MyClassGenerator.java:13)
Note: sun.tools.javac.Main has been deprecated.
1 warning
Running TestHello_1289950330167:
Here's the code:
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileWriter;
import java.net.URL;
import java.net.URLClassLoader;
public class MyClassGenerator {
String generatedClassName = "TestHello_" + System.currentTimeMillis();
String javaFileName = this.generatedClassName + ".java";
public static void main(final String args[]) {
final MyClassGenerator mtc = new MyClassGenerator();
mtc.createIt();
if (mtc.compileIt()) {
System.out.println("Running " + mtc.generatedClassName + ":\n\n");
mtc.runIt();
}
else {
System.out.println(mtc.javaFileName + " is bad.");
}
}
public void loadIt() {
final ClassLoader classLoader = MyClassGenerator.class.getClassLoader();
try {
final Class aClass = classLoader.loadClass(this.generatedClassName);
System.out.println("Loaded " + aClass.getName());
}
catch (final ClassNotFoundException e) {
e.printStackTrace();
}
}
public void createIt() {
try {
final FileWriter aWriter = new FileWriter(this.javaFileName, true);
aWriter.write("public class " + this.generatedClassName + " { }");
aWriter.flush();
aWriter.close();
}
catch (final Exception e) {
e.printStackTrace();
}
}
public boolean compileIt() {
final String[] source = { new String(this.javaFileName) };
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
new sun.tools.javac.Main(baos, source[0]).compile(source);
System.out.print(baos.toString());
return (baos.toString().indexOf("error") == -1);
}
public void runIt() {
try {
final File file = new File(this.javaFileName);
final URLClassLoader classLoader = URLClassLoader.newInstance(new URL[] { file.toURI().toURL() });
final Class<?> cls = Class.forName(this.generatedClassName, true, classLoader);
}
catch (final Exception e) {
e.printStackTrace();
}
}
}
Because it's not in the classpath. Either write it to the classpath (or add its root path to the classpath) or use
URLClassLoader
.Using relative paths in
java.io
is by the way a bad idea. You're dependent on the current working directory which is not controllable from in the code.You are creating a new
URLClassLoader
which points to a concrete file. Expressed as command line arguments, you're doing it like this:And then your code calls this:
A class path is either a JAR file or a folder, not a .java file!
What you should do is creating an URLClassLoader with
".".toURI().toURL()
as the class path, not thejavaFileName
.