6

儘管警告會放棄我目前的行爲,但我目前沒有更好的方法來解決我的問題。我必須生成Java代碼在運行時,然後編譯它,加載它並引用它java類加載器和運行時編譯

問題是生成的代碼導入的代碼已經被系統類加載器加載(我想) - 也就是我的類路徑中的一個jar中存在的代碼。 (我對Java 6,一個Tomcat 6 Web容器內運行),你可能會問自己,爲什麼這是一個問題 - 好肯定不知道 - 但事實是,我得到的編譯錯誤:

/W:/.../parser/v0.5/AssignELParser.java:6: 包com.xxx.yyy.zzz.configuration 不存在

繼從互聯網上一些例子我已經定義以下類別:

class MemoryClassLoader extends ChainedAction { 

    private static final Logger LOG = Logger.getLogger(MemoryClassLoader.class); 

    private LoaderImpl impl; 

    private class LoaderImpl extends ClassLoader { 

     // The compiler tool 
     private final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 

     // Compiler options 
     private final Iterable<String> options = Arrays.asList("-verbose"); 

     // DiagnosticCollector, for collecting compilation problems 
     private final DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>(); 

     // Our FileManager 
     private final MemoryFileManager manager = new MemoryFileManager(this.compiler); 

     public LoaderImpl(File sourceDirectory) { 

      List<Source> list = new ArrayList<Source>(); 

      File[] files = sourceDirectory.listFiles(new FilenameFilter() { 

       @Override 
       public boolean accept(File dir, String name) { 

        return name.endsWith(Kind.SOURCE.extension); 
       } 
      }); 

      for (File file : files) { 
       list.add(new Source(file)); 
      } 

      CompilationTask task = compiler.getTask(null, manager, diagnostics, options, null, list); 
      Boolean compilationSuccessful = task.call(); 

      LOG.info("Compilation has " + ((compilationSuccessful) ? "concluded successfully" : "failed")); 

      // report on all errors to screen 
      for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) { 
       LOG.warn(diagnostic.getMessage(null)); 
      } 
     } 

     @Override 
     protected Class<?> findClass(String name) throws ClassNotFoundException { 
      synchronized (this.manager) { 
       Output output = manager.map.remove(name); 
       if (output != null) { 
        byte[] array = output.toByteArray(); 
        return defineClass(name, array, 0, array.length); 
       } 
      } 
      return super.findClass(name); 
     } 
    } 

    @Override 
    protected void run() { 

     impl = new LoaderImpl(new File(/* Some directory path */)); 

    } 
} 



class MemoryFileManager extends ForwardingJavaFileManager<JavaFileManager> { 

    final Map<String, Output> map = new HashMap<String, Output>(); 

    MemoryFileManager(JavaCompiler compiler) { 
     super(compiler.getStandardFileManager(null, null, null)); 
    } 

    @Override 
    public Output getJavaFileForOutput(Location location, String name, Kind kind, FileObject source) { 

     Output output = new Output(name, kind); 
     map.put(name, output); 

     return output; 
    } 

} 


class Output extends SimpleJavaFileObject { 

    private final ByteArrayOutputStream baos = new ByteArrayOutputStream(); 

    Output(String name, Kind kind) { 
     super(URI.create("memo:///" + name.replace('.', '/') + kind.extension), kind); 
    } 

    byte[] toByteArray() { 
     return this.baos.toByteArray(); 
    } 

    @Override 
    public ByteArrayOutputStream openOutputStream() { 
     return this.baos; 
    } 
} 



class Source extends SimpleJavaFileObject { 


    public Source(File file) { 
     super(file.toURI(), Kind.SOURCE); 
    } 


    @Override 
    public CharSequence getCharContent(boolean ignoreEncodingErrors) { 

     StringBuilder sb = new StringBuilder(""); 
     try { 
      File file = new File(uri); 
      FileReader fr = new FileReader(file); 
      BufferedReader br = new BufferedReader(fr); 

      sb = new StringBuilder((int) file.length()); 
      String line = ""; 
      while ((line = br.readLine()) != null) { 
       sb.append(line); 
       sb.append("\n"); 
      } 
     } catch (FileNotFoundException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 

     return sb.toString(); 
    } 
} 

似乎內部類LoaderImpl通過擴展ClassLoader類並且不調用顯式超級構造函數應引用系統類加載器的父類加載器。

如果這樣做,那麼爲什麼我會收到「運行時」編譯錯誤 - 上面?爲什麼它找不到導入類的代碼?

回答

3

不知道它是否可以幫助,但你有沒有試圖明確指定classpath?

getClassPath() 
{ 
    ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); 
    URL[] urls = ((URLClassLoader) classLoader).getURLs(); 
    StringBuilder buf = new StringBuilder(1000); 
    buf.append("."); 
    String separator = System.getProperty("path.separator"); 
    for (URL url : urls) { 
     buf.append(separator).append(url.getFile()); 
    } 
} 

classPath = buf.toString(); 

然後

options.add("-classpath"); 
options.add(getClassPath()); 

我也看不到你在哪裏傳遞LoaderImpl實例的compiler。它不應該明確地完成嗎?

+0

完美!謝謝 :) – Yaneeve 2009-10-29 15:49:59