我正在尝试制作一个需要使用反射的 Maven 插件。我想要一个项目来运行插件,并给它一个项目中一个类的全名,插件会通过反射加载它以从中获取信息。
但是类加载器有些奇怪,因为当我使用它时找不到类
Class.forName("package.MyClass");
查看“ Maven 类加载指南”,我不太清楚我的插件的类加载器在不同项目中运行时是否可以访问该项目的类。
我正在尝试制作一个需要使用反射的 Maven 插件。我想要一个项目来运行插件,并给它一个项目中一个类的全名,插件会通过反射加载它以从中获取信息。
但是类加载器有些奇怪,因为当我使用它时找不到类
Class.forName("package.MyClass");
查看“ Maven 类加载指南”,我不太清楚我的插件的类加载器在不同项目中运行时是否可以访问该项目的类。
我确信有更好的方法,但这是我如何让它工作的:
在 mojo 顶部的 javadoc 中添加以下内容:@requiresDependencyResolution 运行时
添加一个 MavenProject 参数:
/**
* @parameter expression="${project}"
* @required
* @readonly
*/
private MavenProject project;
然后你可以在运行时获取依赖,并制作你自己的类加载器:
List runtimeClasspathElements = project.getRuntimeClasspathElements();
URL[] runtimeUrls = new URL[runtimeClasspathElements.size()];
for (int i = 0; i < runtimeClasspathElements.size(); i++) {
String element = (String) runtimeClasspathElements.get(i);
runtimeUrls[i] = new File(element).toURI().toURL();
}
URLClassLoader newLoader = new URLClassLoader(runtimeUrls,
Thread.currentThread().getContextClassLoader());
然后你可以使用这个新的类加载器来加载你的类:
Class bundle = newLoader.loadClass("package.MyClass");
您应该考虑使用它来将运行时类路径元素添加到当前类领域。(您可以使用PluginDescriptor
检索类领域。
List<String> runtimeClasspathElements = project.getRuntimeClasspathElements();
ClassRealm realm = descriptor.getClassRealm();
for (String element : runtimeClasspathElements)
{
File elementFile = new File(element);
realm.addURL(elementFile.toURI().toURL());
}
这对我来说非常有效!
正如戴夫所问,这是获得的方法PluginDescriptor
:
/**
* The plugin descriptor
*
* @parameter default-value="${descriptor}"
*/
private PluginDescriptor descriptor;
我今天遇到了这个确切的问题。上述建议对我不起作用,以为我会将我的解决方案提交到列表中。我使用了 HibernateExporter mojo 源,可以在以下位置查看: http: //grepcode.com/file/repo1.maven.org/maven2/org.codehaus.mojo/hibernate3-maven-plugin/2.2/org/codehaus/mojo/ hibernate3/HibernateExporterMojo.java?av=f
/**
* @parameter expression="${project}"
* @required
* @readonly
*/
private MavenProject project;
private ClassLoader getClassLoader() throws MojoExecutionException
{
try
{
List<String> classpathElements = project.getCompileClasspathElements();
classpathElements.add(project.getBuild().getOutputDirectory() );
classpathElements.add(project.getBuild().getTestOutputDirectory() );
URL urls[] = new URL[classpathElements.size()];
for ( int i = 0; i < classpathElements.size(); ++i )
{
urls[i] = new File( (String) classpathElements.get( i ) ).toURI().toURL();
}
return new URLClassLoader(urls, getClass().getClassLoader() );
}
catch (Exception e)//gotta catch em all
{
throw new MojoExecutionException("Couldn't create a classloader.", e);
}
}
public void execute() throws MojoExecutionException
{
ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(getClassLoader());
//... your code here ...
}
还要确保您使用的是正确的 MavenProject 类。将此添加到您的 pom
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-core</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
<version>3.0.3</version>
</dependency>
这对我和 maven3 可以将依赖项放入插件类路径中。
诀窍是使用@Component 注入 PluginDescriptor。否则将无法正确设置。
@Component
private MavenProject project;
@Component
private PluginDescriptor descriptor;
private void addDependenciesToClasspath(String artifactId) {
for (Artifact artifact : project.getDependencyArtifacts()) {
if (artifact.getArtifactId().equals(artifactId)) {
try {
final URL url = artifact.getFile().toURI().toURL();
final ClassRealm realm = descriptor.getClassRealm();
realm.addURL(url);
}
catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}
}
}
没关系,我们需要自己制作类 加载器Custom Classloaders