I\'m trying to make a maven plugin that needs to use reflection. I want a project to run the plugin, and give it the full name of a class in the project, and the plugin will
I ran across this exact issue, today. The above suggestions didn't work for me, thought I would submit my solution to the list. I used the HibernateExporter mojo source which can be viewed at: 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 ...
}
Also make sure you are using the right MavenProject class. add this to your 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>
You should consider using this to add the runtime class path elements to the current class realm. (You can use the PluginDescriptor
to retrieve the class realm.
List<String> runtimeClasspathElements = project.getRuntimeClasspathElements();
ClassRealm realm = descriptor.getClassRealm();
for (String element : runtimeClasspathElements)
{
File elementFile = new File(element);
realm.addURL(elementFile.toURI().toURL());
}
This worked perfectly for me!
As Dave asked, here is the way to get the PluginDescriptor
:
/**
* The plugin descriptor
*
* @parameter default-value="${descriptor}"
*/
private PluginDescriptor descriptor;
I'm sure there's a better way, but here's how I got it to work:
Add the following to the javadoc at the top of your mojo: @requiresDependencyResolution runtime
Add a MavenProject parameter:
/**
* @parameter expression="${project}"
* @required
* @readonly
*/
private MavenProject project;
Then you can get the dependencies at runtime, and make your own classloader:
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());
Then you can load your class using this new classloader:
Class bundle = newLoader.loadClass("package.MyClass");
This worked for me and maven3 to get dependencies into the plugin classpath.
The trick is to use @Component to inject the PluginDescriptor. Otherwise it will not be set up correctly.
@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);
}
}
}
}