2010-11-16 8 views
2

В следующем примере я пытаюсь использовать 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(); 
     } 
    } 
} 

ответ

6

Потому что это не в пути к классам. Либо напишите его в путь к классам (или добавьте его корневой путь к пути к классам), либо используйте URLClassLoader.

File root = new File("."); 
URLClassLoader classLoader = URLClassLoader.newInstance(new URL[] { root.toURI().toURL() }); 
Class<?> cls = Class.forName(generatedClassName, true, classLoader); 

Использование относительных путей в java.io, кстати, плохая идея. Вы зависите от текущего рабочего каталога, который не управляется из кода.

+0

Я все еще получаю сообщение об ошибке. Я обновил код с вашим предложением. Я бы очень хотел, чтобы это можно было сделать динамически. –

+0

Моя ошибка, вы должны установить корневой путь как путь к классам, а не сам файл. Я исправил пример кода. Однако я бы рекомендовал использовать фиксированный корневой путь. Быть зависимым от текущего рабочего каталога - плохая идея. Вы можете, кстати, найти другой пример в [этом ответе] (http://stackoverflow.com/questions/1981750/loading-external-source-code-and-using-them-internally-by-re-compiling-or- someth/1981919 # 1981919). – BalusC

+0

Если я поместил свой сгенерированный класс в пакет, будет ли это имя пакета использоваться вместо '.'? –

1

Вы создаете новый URLClassLoader, который указывает на конкретный файл. Выраженный в качестве аргументов командной строки, вы делаете это так:

java -cp file:///foo/bar/TestHello_1289950330167.java 

И тогда ваш код вызывает это:

Class.forName("TestHello_1289950330167",true,cl); 

Путь класса либо JAR-файл или папку , не файл .java!

Что вам нужно сделать, это создать URLClassLoader с ".".toURI().toURL() как путь к классу, а не javaFileName.

Смежные вопросы