簡體   English   中英

Java 編譯器 API 類加載器

[英]Java compiler API ClassLoader

我正在嘗試使用 Java 編譯器 API 來編譯一些 java ZA2F2ED4F8EBC2CBB4ZC2A。 那個 class 從 jar 文件中導入了一些包,這些包可以由上下文 ClassLoader 加載,我們稱他為 X,它不是系統類加載器。 當我運行編譯時,編譯器抱怨無法識別導入。 我試圖指定 fileManager 來傳遞類加載器,但它沒有幫助。

當調用compile方法時,它首先打印“CLASS LOADED”,因此上下文ClassLoader可以找到依賴class。 但是,編譯本身失敗(我收到“編譯失敗”消息)並且在編譯期間我收到如下錯誤:

/path/to/my/Source.java:3: package my.dependency 不存在 import my.dependency.MyClass; ^

我究竟做錯了什么? 將自定義類加載器傳遞給編譯任務的正確方法是什么? 我無法從 ClassLoader 中提取 URL,因為它不是 URLClassLoader。

我的方法在這里:

public void compile(List<File> filesToCompile) {
       JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

       StandardJavaFileManager stdFileManager =
               compiler.getStandardFileManager(null, null, null);
       Iterable<? extends JavaFileObject> fileObjects = stdFileManager
               .getJavaFileObjectsFromFiles(filesToCompile);

       FileManagerImpl fileManager = new FileManagerImpl(stdFileManager);

       CompilationTask task = compiler.getTask(null, fileManager, null, null, null, fileObjects);
       Boolean result = task.call();
       if (result == true) {
           System.out.println("Compilation has succeeded");
       } else {
           System.out.println("Compilation FAILED");
       }
}

private final class FileManagerImpl extends ForwardingJavaFileManager<JavaFileManager> {

      public FileManagerImpl(JavaFileManager fileManager) {
           super(fileManager);
      }

      @Override
      public ClassLoader getClassLoader(JavaFileManager.Location location) {
          ClassLoader def = getContextClassLoader();
          try {
               def.loadClass("my.dependency.MyClass");
               System.out.println("CLASS LOADED");
          } catch (ClassNotFoundException ex) {
               System.out.println("NOT LOADED");
          }
          return def;
      }
}

要點是,當 class 加載器加載類時,javac 將調用JavaFileManager#list()以獲取 package 中所有文件的列表。

因此,要使用自定義 class 加載器,您需要修改(或擴展)它以覆蓋JavaFileManager#list() 希望您可以重用一些用於 class 加載的邏輯。

您可能希望使用自己的JavaFileObject實現來表示 class 對象。 然后,您將需要覆蓋JavaFileManager#inferBinaryName() (否則 javac 版本將崩潰)。 您的JavaFileObject實現還需要覆蓋(至少) JavaFileObject#openInputStream

這里有一些提示: http://atamur.blogspot.be/2009/10/using-built-in-javacompiler-with-custom.html

另外,不要讓你的生活變得更艱難,並擴展ForwardingJavaFileManagerSimpleJavaFileObject

作為參考,這里是一個示例實現:

  @Override public Iterable<JavaFileObject> list(Location location,
    String packageName, Set<JavaFileObject.Kind> kinds, boolean recurse)
  throws IOException
  {
    Iterable<JavaFileObject> stdResults =
      fileManager.list(location, packageName, kinds, recurse);

    if (location != StandardLocation.CLASS_PATH
    ||  !kinds.contains(JavaFileObject.Kind.CLASS))
    {
        return stdResults;
    }

    Set<JavaFileObject> additional = pkgObjects.get(packageName);

    if (additional == null || additional.isEmpty()) {
      return stdResults;
    }

    List<JavaFileObject> out = new ArrayList<>();

    for (JavaFileObject obj : additional) {
      out.add(obj);
    }
    for (JavaFileObject obj : stdResults) {
      out.add(obj);
    }

    return out;
  }

其中pkgObjects是 map 從 package 名稱到JavaFileObject 您填充此 map 的方式取決於您的 class 裝載機的工作方式。

For loading the class from different jar file you could try with Reflection API it is easy way..refer the following link http://download.oracle.com/javase/tutorial/reflect/index.html ..

這個問題有答案 您必須使用getTask()方法通過選項列表設置類路徑(如已接受的答案中詳細描述的那樣)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM