В следующем примере я пытаюсь использовать sun.tools.javac.Main
для динамической компиляции создаваемого класса, а затем создать экземпляр объекта этого класса и вызвать метод. До сих пор я даже не мог пройти загрузку сгенерированного класса. Я получаю следующее исключение в Eclipse:Почему я получаю ClassNotFoundException при использовании Class.forName (...)?
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:
Вот код:
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();
}
}
}
Я все еще получаю сообщение об ошибке. Я обновил код с вашим предложением. Я бы очень хотел, чтобы это можно было сделать динамически. –
Моя ошибка, вы должны установить корневой путь как путь к классам, а не сам файл. Я исправил пример кода. Однако я бы рекомендовал использовать фиксированный корневой путь. Быть зависимым от текущего рабочего каталога - плохая идея. Вы можете, кстати, найти другой пример в [этом ответе] (http://stackoverflow.com/questions/1981750/loading-external-source-code-and-using-them-internally-by-re-compiling-or- someth/1981919 # 1981919). – BalusC
Если я поместил свой сгенерированный класс в пакет, будет ли это имя пакета использоваться вместо '.'? –