2013-06-22 59 views
0

我開始從一個著名的Java構建系統切換到搖籃建立我的所有項目,勉強2小時進去後,我已經能夠公佈我的項目之一的新版本沒有問題 - 微風。使用gradle構建ServiceLoader文件:howto?

但現在我遇到困難。總之,我需要複製this Maven plugin的功能,該功能爲啓用ServiceLoader的服務生成必要的文件。

簡而言之:給定基類foo.bar.MyClass,它會生成一個名爲META-INF/services/foo.bar.MyClass的文件,其內容是當前項目中實現該基類的接口/擴展的一組類。這樣的文件看起來像:

com.mycompany.MyClassImpl 
org.othercompany.MyClassImpl 

爲了做到這一點,它使用我不知道是什麼的類加載器,加載Class對象爲com.myCompany.MyClassImpl或什麼,並檢查這個類是否實現想要的界面。

我試圖做同樣的搖籃。谷歌搜索的時間使我this plugin,但它的作者討論了一點之後,看來這個插件能夠合併這樣的文件,而不是創建它們。所以,我必須自己做...

我是一個真正的初學者與Gradle和Groovy,這並沒有幫助!這是我目前的代碼,鏈接到完整的build.gradlehere;輸出(我設法得到某種方式;不能從一個乾淨的目錄)(並請忍受我...我做Java,我最後很高興; Groovy對我來說是全新的):

/* 
* TEST CODE 
*/ 

final int CLASS_SUFFIX = ".class".length(); 
final URLClassLoader classLoader = this.class.classLoader; 
// Where the classes are: OK 
final File classesDir = sourceSets.main.output.classesDir; 
final String basePath = classesDir.getCanonicalPath(); 

// Add them to the classloader: OK 
classLoader.addURL(classesDir.toURI().toURL()) 

// Recurse over each file 
classesDir.eachFileRecurse { 
    // You "return" from a closure, you do not "continue"... 
    if (!isPotentialClass(it)) 
     return; 

    // Transform into a class name 
    final String path = it.getAbsolutePath(); 
    final String name = path.substring(basePath.length() + 1); 
    final String className = name.substring(0, name.length() - CLASS_SUFFIX) 
     .replace('/', '.'); 

    // Try and load it 
    try { 
     classLoader.loadClass(className); 
     println(className); 
    } catch (NoClassDefFoundError ignored) { 
     println("failed to load " + className + ": " + ignored); 
    } 
} 

boolean isPotentialClass(final File file) 
{ 
    return file.isFile() && file.name.endsWith(".class") 
} 

輸出:

com.github.fge.msgsimple.InternalBundle 
failed to load com.github.fge.msgsimple.bundle.MessageBundle: java.lang.NoClassDefFoundError: com/github/fge/Frozen 
failed to load com.github.fge.msgsimple.bundle.MessageBundleBuilder: java.lang.NoClassDefFoundError: com/github/fge/Thawed 
com.github.fge.msgsimple.bundle.PropertiesBundle$1 
com.github.fge.msgsimple.bundle.PropertiesBundle 
com.github.fge.msgsimple.provider.MessageSourceProvider 
com.github.fge.msgsimple.provider.LoadingMessageSourceProvider$1 
com.github.fge.msgsimple.provider.LoadingMessageSourceProvider$2 
com.github.fge.msgsimple.provider.LoadingMessageSourceProvider$3 
com.github.fge.msgsimple.provider.LoadingMessageSourceProvider$Builder 
com.github.fge.msgsimple.provider.LoadingMessageSourceProvider 
com.github.fge.msgsimple.provider.MessageSourceLoader 
com.github.fge.msgsimple.provider.StaticMessageSourceProvider$Builder 
com.github.fge.msgsimple.provider.StaticMessageSourceProvider$1 
com.github.fge.msgsimple.provider.StaticMessageSourceProvider 
com.github.fge.msgsimple.source.MessageSource 
com.github.fge.msgsimple.source.MapMessageSource$Builder 
com.github.fge.msgsimple.source.MapMessageSource$1 
com.github.fge.msgsimple.source.MapMessageSource 
com.github.fge.msgsimple.source.PropertiesMessageSource 
com.github.fge.msgsimple.locale.LocaleUtils 
com.github.fge.msgsimple.serviceloader.MessageBundleFactory 
com.github.fge.msgsimple.serviceloader.MessageBundleProvider 
:compileJava UP-TO-DATE 

的問題是在兩個第一線:FrozenThawed在不同的項目,這是在編譯的類路徑,但不是在classpath中我設法到目前爲止搶。因此,這些類甚至無法加載。

如何修改該代碼以便具有完整的編譯類路徑?是我的第一個問題。第二個問題:如何在編譯過程中將代碼插入到構建過程中?

回答

1

下面是一些提示:

  • 創建一個新的URLClassLoader,而不是重用現有的一個。
  • sourceSets.main.compileClasspath(它是Iterable<File>)而不是classesDir初始化類加載器。
  • 將代碼轉換爲Gradle任務類。有關更多信息,請參閱Gradle User Guide中的「編寫簡單任務類」。

理想情況下,您應該使用類似ASM的庫來分析代碼,而不是使用類加載器。爲避免無法加載類的情況,因爲它在內部引用了不在編譯類路徑中的類,您可能需要使用sourceSets.main.runtimeClasspath來初始化類加載器。

+0

好的,我試過這個:'sourceSets.main.compileClasspath.each {println(it)}' - >它只打印我依賴的罐子......所以,基本上,我必須將jar網址製作成它們,然後將其饋送到我創建的新類路徑中,對嗎?我創建了一個「URL」的Java數組(你怎麼在Groovy中做到這一點?),使用'URLClassLoader.newInstance()',我應該能夠走得更遠? (感謝您的用戶指南鏈接,我也會閱讀它,我只是想先說出「類別檢測」的事情!) – fge

+0

其實您還需要'classesDir'。可能最好使用'runtimeClasspath'來初始化類加載器,它已經包含'classesDir'。要將列表轉換爲數組,請使用'list as URL []'。如果您在Java中感覺更舒適,則可以使用Java編寫任務類。 –

+0

在這一點上,我已經知道我需要'classesDir';)好奇:你如何用'runtimeClasspath'啓動一個類加載器?我猜剩下的只是'URLClassLoader'實例上的'.addURL()'? – fge