Search code examples
javamavenpluginsclasspathclassloader

Access project classes from a maven plugin


I'm making a maven plugin that run in test phase, in pom.xml configuration of a project that uses my plugin, I'm setting a class canonical name that I want to use to run that class from my plugin, basically I'm making a way to have a dynamic class loading of classes inside the project from my plugin.

Class clazz = Class.forName("... class from pom.xml ...")

When I run it I receive the expectable "ClassNotFoundException", seems the class loader are not the same or not shared.

There is a way to do it? Like capture the class loader from the project or receive it by dependency injection into my plugin? What is the best way?


Solution

  • We can use the Hibernate implementation in mojo can be used as a reference to make it:

    Checkout the source code here: http://grepcode.com/file/repo1.maven.org/maven2/org.codehaus.mojo/hibernate3-maven-plugin/2.2/org/codehaus/mojo/hibernate3/HibernateExporterMojo.java#HibernateExporterMojo.getClassLoader%28%29

        private ClassLoader getClassLoader(MavenProject project)
        {
            try
            {
                List 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 ) ).toURL();
                }
                return new URLClassLoader( urls, this.getClass().getClassLoader() );
            }
            catch ( Exception e )
            {
                getLog().debug( "Couldn't get the classloader." );
                return this.getClass().getClassLoader();
            }
        }
    

    To capture the "project" object, we can use the mojo dependency injection:

    /**
     * Dependency injected
     */
     @Parameter(defaultValue = "${project}")
     public MavenProject project;
    

    And use it to load some class in project class loader:

    getClassLoader(this.project).loadClass("com.somepackage.SomeClass")