[英]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
另外,不要讓你的生活變得更艱難,並擴展ForwardingJavaFileManager
和SimpleJavaFileObject
。
作為參考,這里是一個示例實現:
@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.