Friday, July 9, 2010

Sharing Resources in Maven

Today I needed to figure out the best way to share resources across multiple maven modules. We have previously done it 2 different ways, neither of which I thought were very good. The first way was using a relative path to reach across to the modules resource directory (usually not a good practice in maven). It went something like this:

1
2
3
4
5
<resources>
    <resource>
        <directory>../module1/src/main/resources</directory>
    </resource>
</resources>

The second way was using the infamous maven assembly plugin. I typically avoid the assembly plugin like I avoid writing Assembly. Plus I prefer avoiding 100 extra lines of XML on something so trivial. Luckily, the Sonatype guys apparently knew this and have come up with a more efficient way of sharing resources using the maven-remote-resources-plugin. It has the advantages of requiring a lot less XML lifting and it's nicely integrated into the maven lifecycle. I did run into one small issue trying to get it to work. By default it only copies **/*.txt files from src/main/resources. For several minutes, I couldn't figure how why it wasn't working until I added an includes for **/*.xml. Then it worked perfectly. Here is the end result:

Creating a resource bundle
Add the following to your POM which is going to create the resource bundle.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<plugin>     
    <artifactid>maven-remote-resources-plugin</artifactid>
    <version>1.1</version>
    <executions>
        <execution>
            <goals>
                <goal>bundle</goal>
            </goals>
            <configuration>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </configuration>
        </execution>
    </executions>
</plugin>

You now should see the following message in your mvn output while running mvn clean install.

[remote-resources:bundle {execution: default}]

This produces a /target/classes/META-INF/maven/remote-resources.xml file which contains references to the resource files. For example,
1
2
3
<remoteresources>
    <remoteresource>test.xml</remoteresource>
</remoteresources>
Consuming Resource Bundle
Add the following to the POM which needs to consume the new resource bundle.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<plugin>     
    <artifactid>maven-remote-resources-plugin</artifactid>
    <version>1.1</version>
    <executions>
        <execution>
            <goals>
                <goal>process</goal>
            </goals>
            <configuration>
                <resourcebundles>
                    <resourcebundle>com.lorenzen:lorenzen-core:${pom.version}</resourcebundle>
                </resourcebundles>
            </configuration>
        </execution>
    </executions>
</plugin>

You now should see the following message in your mvn output while running mvn clean install.

[remote-resources:process {execution: default}]

You should now be able to look into your second modules /target/classes directory and see test.xml.