问题描述
我正在尝试在执行 Maven mojo 期间加载项目类。
不幸的是,这个操作失败了,因为类加载器缺少一个被引用的类。 环顾四周,我已经找到了方法 Maven mojo plugin to load class from hosting project 和 Maven plugin can't load class
private ClassLoader getClassLoader(final MavenProject project) {
try {
final List<URL> classpathUrls = new ArrayList<>();
// adding the projects dependency jars
final Set<Artifact> artifacts = getProject().getDependencyArtifacts();
for (final Artifact artifact : artifacts) {
classpathUrls.add(artifact.getFile().toURI().toURL());
}
// adding the projects classes itself
final List<String> classpathelements = project.getCompileClasspathelements();
classpathelements.add(project.getBuild().getoutputDirectory());
classpathelements.add(project.getBuild().getTestOutputDirectory());
for (final String classpathelement : classpathelements) {
classpathUrls.add(new File(classpathelement).toURI().toURL());
}
// creating a class loader
final URL urls[] = new URL[classpathUrls.size()];
for (int i = 0; i < classpathUrls.size(); ++i) {
urls[i] = classpathUrls.get(i);
}
return new urlclassloader(urls,this.getClass().getClassLoader());
} catch (final Exception e) {
getLog().debug("Couldn't get the classloader.");
return this.getClass().getClassLoader();
}
}
加载失败的类是接口“org.bson.codecs.Codec”的实现,它包含在“org.mongodb:bson”中,通过依赖隐式导入:
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver-sync</artifactId>
<version>4.1.1</version>
<scope>provided</scope>
</dependency>
这个依赖对另一个jar有一个依赖(范围:提供),包含提到的接口,可以在maven依赖树中看到:
$> mvn dependency:tree
[INFO] net.my.project:my-project:jar:1.0-SNAPSHOT
[INFO] +- org.mongodb:mongodb-driver-sync:jar:4.1.1:provided
[INFO] | +- org.mongodb:bson:jar:4.1.1:provided
[INFO] | \- org.mongodb:mongodb-driver-core:jar:4.1.1:provided
当我查看创建的类加载器的类路径元素时,我看到 mongodb-driver-sync.jar 被包含在内,但由于它声明了“org.mongodb:bson”依赖范围,提供它的接口是仍然不在类路径中。
所以,最后一个问题是:如何加载一个从“间接”依赖项中引用类的类?
解决方法
我注意到了
project.getArtifacts()
是空的,即使 javadoc 说它应该包含所有依赖项(延迟填充)。
因此,通过额外的研究,我发现 Custom Maven Plugin development - getArtifacts is empty though dependencies are included 建议调整 @Mojo 注释:
@Mojo(name = "mojoName",requiresDependencyResolution = ResolutionScope.COMPILE)
调整注解后,使用“project.getCompileClasspathElements();”就足够了,完全没有必要再遍历工件了。