6

私の現在の行動方針を落とす警告が出ていますが、私は現在、私の問題を解決する良い方法は見当たりません。 I Javaコードを実行時にコンパイルし、コンパイルしてロードし、を参照する必要があります。Javaクラスローダーとランタイムコンパイル

問題は、生成されたコードがシステムクラスローダーによって読み込まれたコードをインポートするということです。つまり、クラスパス上のjarファイルの1つにコードが存在します。それが問題である理由 (Iは、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(); 
    } 
} 

ClassLoaderクラスを拡張し、明示的なスーパーコンストラクターを呼び出さないことで内部クラスLoaderImplが親クラスローダーとしてシステムクラスローダーを参照する必要があるようです。

もしそうなら、なぜ上記の「ランタイム」コンパイルエラーが発生するのですか?インポートされたクラスのコードが見つからないのはなぜですか?

答えて

3

クラスパスを明示的に指定しようとしていますか?

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()); 

あなたはcompilerLoaderImplインスタンスを渡すんどこにも見ることができません。明示的にしてはいけませんか?

+0

完璧!ありがとう:) – Yaneeve

関連する問題