Search code examples
javamavenmaven-3

Accessing a project resource from a plugin in Maven


I've written a Maven plugin which when running standalone is working fine. I have some custom XML resource files within the plugin source code that are visible and accessible to the plugin when testing (Plugin POM below). So I install the plugin and all is well.

Now I create a new project that refers to the newly installed plugin (Project POM below). I have some custom XML resource files similar to those embedded within the plugin project.

The project has the following structure:

tester
|   pom.xml
|
+---src
|   +---main
|   |   +---java
|   |   |   \---[BLAH}
|   |   |
|   |   \---resources
|   |           tester-catalog-env.xml
|   |
|   \---test
|       \---java
|           \---[BLAH]

Within the plugin I have the following method:

    public TesterProcessCatalog getTesterProcessCatalog(Properties properties) throws TesterDataSourceException {
        try {
            InputStream in = getClass().getClass().getResourceAsStream("tester-catalog-env.xml");
            Reader reader = ReaderFactory.newXmlReader(in);
            return readCatalog(reader);

        } catch (IOException e) {
            throw new TesterDataSourceException("Error reading catalog", e);
        }
    }

The line:

InputStream in = getClass().getClass().getResourceAsStream("tester-catalog-env.xml");

is returning null when run from the project using mvn tester:test (as defined in the plugin mojo) even though I can see that the resource is present on the classpath. I've tried the following

InputStream in = getClass().getClass().getResourceAsStream("/tester-catalog-env.xml");

and that also returns null.

If I copy the resource file over to the plugin resource directory and run, it works fine.

Ultimately what I'm trying to achieve is to have multiple config files in the projects resources directory (ie tester-catalog-xxx.xml - where xxx can be a new file created by the user) that when a command like mvn tester:test -DprocessCatalog=env2 is run the file called tester-catalog-env2.xml will be loaded.

Any ideas on what I'm doing wrong?

Maven Info

Apache Maven 3.0.4 (r1232337; 2012-01-17 10:44:56+0200)
Maven home: C:\Apps\apache-maven-3.0.4
Java version: 1.6.0_35, vendor: Sun Microsystems Inc.
Java home: C:\java\jdk1.6.0_35\jre
Default locale: en_GB, platform encoding: Cp1252
OS name: "windows xp", version: "5.1", arch: "x86", family: "windows"

Plugin POM

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.testing.tester.maven</groupId>
    <artifactId>tester</artifactId>
    <packaging>maven-plugin</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>tester Maven Mojo</name>
    <url>http://maven.apache.org</url>
    <dependencies>
        <dependency>
            <groupId>org.apache.maven</groupId>
            <artifactId>maven-plugin-api</artifactId>
            <version>2.0</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>2.2-beta-5</version>
        </dependency>
        <dependency>
            <groupId>org.codehaus.plexus</groupId>
            <artifactId>plexus-component-annotations</artifactId>
            <version>1.5.5</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.1</version>
        </dependency>
        <dependency>
            <groupId>com.sun</groupId>
            <artifactId>tools</artifactId>
            <version>1.6</version>
            <scope>system</scope>
            <systemPath>C:\java\jdk1.6.0_35\lib\tools.jar</systemPath>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>commons-cli</groupId>
            <artifactId>commons-cli</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>com.brsanthu</groupId>
            <artifactId>data-exporter</artifactId>
            <version>1.0.0</version>
            <!-- http://code.google.com/p/data-exporter/wiki/UserGuide -->
            <!-- mvn install:install-file -DgroupId=com.brsanthu -DartifactId=data-exporter -Dversion=1.0.0 -Dpackaging=jar -Dfile=http://data-exporter.googlecode.com/files/data-exporter-1.0.0.jar-->
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.plexus</groupId>
                <artifactId>plexus-component-metadata</artifactId>
                <version>1.5.5</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>generate-metadata</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-source-plugin</artifactId>
                <executions>
                    <execution>
                        <id>attach-sources</id>
                        <goals>
                            <goal>jar</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

Project POM

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.testing.tester</groupId>
  <artifactId>tester</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>tester</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
      <dependency>
          <groupId>com.testing.tester.maven</groupId>
          <artifactId>tester</artifactId>
          <version>1.0-SNAPSHOT</version>
      </dependency>
  </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>com.testing.tester.maven</groupId>
                <artifactId>tester</artifactId>
                <version>1.0-SNAPSHOT</version>
            </plugin>
        </plugins>
    </build>
</project>

Solution

  • I have found a working solution. This post details the steps required.

    Basically I added the following class to the plugin (I've removed the references to LOGGER in the original post)

        /**
         * A custom ComponentConfigurator which adds the project's runtime classpath elements
         * to the
         *
         * @author Brian Jackson
         * @since Aug 1, 2008 3:04:17 PM
         *
         * @plexus.component role="org.codehaus.plexus.component.configurator.ComponentConfigurator"
         *                   role-hint="include-project-dependencies"
         * @plexus.requirement role="org.codehaus.plexus.component.configurator.converters.lookup.ConverterLookup"
         *                   role-hint="default"
         */
        public class IncludeProjectDependenciesComponentConfigurator extends AbstractComponentConfigurator { 
    
            public void configureComponent( Object component, PlexusConfiguration configuration,
                                            ExpressionEvaluator expressionEvaluator, ClassRealm containerRealm,
                                            ConfigurationListener listener )
                throws ComponentConfigurationException {
    
                addProjectDependenciesToClassRealm(expressionEvaluator, containerRealm);
    
                converterLookup.registerConverter( new ClassRealmConverter( containerRealm ) );
    
                ObjectWithFieldsConverter converter = new ObjectWithFieldsConverter();
    
                converter.processConfiguration( converterLookup, component, containerRealm.getClassLoader(), configuration,
                                                expressionEvaluator, listener );
            }
    
            private void addProjectDependenciesToClassRealm(ExpressionEvaluator expressionEvaluator, ClassRealm containerRealm) throws ComponentConfigurationException {
                List<String> runtimeClasspathElements;
                try {
                    //noinspection unchecked
                    runtimeClasspathElements = (List<String>) expressionEvaluator.evaluate("${project.runtimeClasspathElements}");
                } catch (ExpressionEvaluationException e) {
                    throw new ComponentConfigurationException("There was a problem evaluating: ${project.runtimeClasspathElements}", e);
                }
    
                // Add the project dependencies to the ClassRealm
                final URL[] urls = buildURLs(runtimeClasspathElements);
                for (URL url : urls) {
                    containerRealm.addConstituent(url);
                }
            }
    
            private URL[] buildURLs(List<String> runtimeClasspathElements) throws ComponentConfigurationException {
                // Add the projects classes and dependencies
                List<URL> urls = new ArrayList<URL>(runtimeClasspathElements.size());
                for (String element : runtimeClasspathElements) {
                    try {
                        final URL url = new File(element).toURI().toURL();
                        urls.add(url);
                    } catch (MalformedURLException e) {
                        throw new ComponentConfigurationException("Unable to access project dependency: " + element, e);
                    }
                }
    
                // Add the plugin's dependencies (so Trove stuff works if Trove isn't on
                return urls.toArray(new URL[urls.size()]);
            }
    
        }
    

    then added

    @configurator include-project-dependencies
    

    To my mojo declaration and it works!