我开始从一个着名的Java构建系统切换到Gradle来构建我的所有项目,在经过两个小时之后,我已经能够毫无问题地发布我的一个项目的新版本 - - 轻而易举。
但现在我遇到了一个困难。简而言之,我需要复制this Maven plugin的功能,该功能为启用了ServiceLoader
的服务生成必要的文件。
简而言之:给定基类foo.bar.MyClass
,它会生成一个名为META-INF/services/foo.bar.MyClass
的文件,其内容是当前项目中实现该接口/扩展该基类的一组类。这样的文件看起来像:
com.mycompany.MyClassImpl
org.othercompany.MyClassImpl
为了做到这一点,它使用我不知道什么是类加载器,为Class
加载com.myCompany.MyClassImpl
对象或者其他什么,并检查这个类是否实现了所需的接口。
我正在尝试在Gradle中做同样的事情。几小时的谷歌搜索引导我this plugin,但在与其作者讨论了一下后,看来这个插件能够合并这样的文件,而不是创建它们。所以,我必须自己做...
我是Gradle和Groovy的真正初学者,但没有帮助!这是我当前的代码,链接到完整的build.gradle
here;输出(我设法以某种方式获得;从一个干净的目录不起作用)如下所示(请耐心等待我...我做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
问题在于前两行:Frozen
和Thawed
在不同的项目中,它位于编译类路径中,但不在我设法抓取的类路径中...这样,这些类甚至无法加载。
如何修改该代码以使完整的编译类路径可用?是我的第一个问题。第二个问题:如何将代码插入到构建过程中?
答案 0 :(得分:1)
以下是一些提示:
URLClassLoader
,而不是重复使用现有的。{/ li>
sourceSets.main.compileClasspath
(Iterable<File>
)而不是classesDir
初始化类加载器。理想情况下,您使用像ASM这样的库来分析代码,而不是使用类加载器。为了避免因为内部引用不在编译类路径上的类而无法加载类的情况,您可能希望用sourceSets.main.runtimeClasspath
初始化类加载器。