Handling Classpath Resources

Another common use case, which requires no changes to the POM shown previously, is the packaging of resources into a JAR file. For this common task, Maven again uses the standard directory layout. This means that by adopting Maven’s standard conventions, you can package resources within JARs, simply by placing those resources in a standard directory structure.

In the following example, you need to add the directory src/main/resources. That is where you place any resources you wish to package in the JAR. The rule employed by Maven is that all directories or files placed within the src/main/resources directory are packaged in your JAR with the exact same structure, starting at the base of the JAR.


Figure 1-2: Directory structure after adding the resources directory

You can see in the preceding example that there is a META-INF directory with an application.properties file within that directory. If you unpacked the JAR that Maven created you would see the following:


Figure 1-3: Directory structure of the JAR file created by Maven

The original contents of src/main/resources can be found starting at the base of the JAR and the application.properties file is there in the META-INF directory. You will also notice some other files like META-INF/MANIFEST.MF, as well as a pom.xml and pom.properties file. These come standard with the creation of a JAR in Maven. You can create your own manifest if you choose, but Maven will generate one by default if you don’t. If you would like to try this example, simply create the resources and META-INF directories and create an empty file called application.properties inside. Then run mvn install and examine the jar file in the target directory.

The pom.xml and pom.properties files are packaged up in the JAR so that each artifact produced by Maven is self-describing and also allows you to utilize the metadata in your own application, should the need arise. One simple use might be to retrieve the version of your application. Operating on the POM file would require you to use Maven utilities, but the properties can be utilized using the standard Java APIs.

Handling Test Classpath Resources

To add resources to the classpath for your unit tests, follow the same pattern as you do for adding resources to the JAR, except place resources in the src/test/resources directory. At this point you have a project directory structure that should look like the following:


Figure 1-4: Directory structure after adding test resources

In a unit test, you could use a simple snippet of code like the following for access to the resource required for testing:

[...]
// Retrieve resource
InputStream is = getClass().getResourceAsStream( "/test.properties" );

// Do something with the resource

[...]

To override the manifest file yourself, you can use the following configuration for the maven-jar-plugin:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <configuration>
        <archive>
            <manifestFile>META-INF/MANIFEST.MF</manifestFile>
        </archive>
    </configuration>
</plugin>

Filtering Classpath Resources

Sometimes a resource file will need to contain a value that can be supplied at build time only. To accomplish this in Maven, you can filter your resource files dynamically by putting a reference to the property that will contain the value into your resource file using the syntax ${}. The property can be either one of the values defined in your pom.xml, a value defined in the user’s settings.xml, a property defined in an external properties file, or a system property.

To have Maven filter resources when copying, simply set filtering to true for the resource directory in your pom.xml:

<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.mycompany.app</groupId>
    <artifactId>my-app</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>Maven Quick Start Archetype</name>
    <url>http://maven.apache.org</url>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
            </resource>
        </resources>
    </build>
</project>

You’ll notice that the build, resources, and resource elements – which weren’t there before – have been added. In addition, the POM has to explicitly state that the resources are located in the src/main/resources directory. All of this information was previously provided as default values and now must be added to the pom.xml to override the default value for filtering and set it to true.

To reference a property defined in your pom.xml, the property name uses the names of the XML elements that define the value. So ${project.name} refers to the name of the project, ${project.version} refers to the version of the project, and ${project.build.finalName} refers to the final name of the file created, when the built project is packaged. In fact, any element in your POM is available when filtering resources.
To continue the example, create an src/main/resources/META-INF/application.properties file, whose values will be supplied when the resource is filtered as follows:

# application.properties
application.name=${project.name}
application.version=${project.version}

With that in place, you can execute the following command (process-resources is the build life cycle phase where the resources are copied and filtered):

mvn process-resources

The application.properties file under target/classes, which will eventually go into the JAR looks like this:

# application.properties
application.name=Maven Quick Start Archetype
application.version=1.0-SNAPSHOT

To reference a property defined in an external file, all you need to do is add a reference to this external file in your pom.xml. First, create an external properties file and call it src/main/filters/filter.properties:

# filter.properties
my.filter.value=hello!

Next, add a reference to this new file in the pom.xml file:

<build>
    <filters>
        <filter>src/main/filters/filter.properties</filter>
    </filters>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <filtering>true</filtering>
        </resource>
    </resources>
</build>

Then, add a reference to this property in the application.properties file as follows:

# application.properties
application.name=${project.name}
application.version=${project.version}
message=${my.filter.value}

The next execution of the mvn process-resources command will put the new property value into application.properties. As an alternative to defining the my.filter.value property in an external file, you could have defined it in the properties section of your pom.xml and you’d get the same effect (notice you don’t need the references to src/main/filters/filter.properties either):

<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.mycompany.app</groupId>
    <artifactId>my-app</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>Maven Quick Start Archetype</name>
    <url>http://maven.apache.org</url>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
            </resource>
        </resources>
    </build>
    <properties>
        <my.filter.value>hello</my.filter.value>
    </properties>
</project>

Filtering resources can also retrieve values from system properties; either the system properties built into Java (like java.version or user.home), or properties defined on the command line using the standard Java -D parameter. To continue the example, change the application.properties file to look like the following:

# application.properties
java.version=${java.version}
command.line.prop=${command.line.prop}

Now, when you execute the following command (note the definition of the command.line.prop property on the command line), the application.properties file will contain the values from the system properties.

mvn process-resources "-Dcommand.line.prop=hello again"

Preventing Filtering of Binary Resources

Sometimes there are classpath resources that you want to include in your JAR, but you do not want them filtered. This is most often the case with binary resources, for example image files.

If you had a src/main/resources/images that you didn’t want to be filtered, then you would create a resource entry to handle the filtering of resources with an exclusion for the resources you wanted unfiltered. In addition you would add another resource entry, with filtering disabled, and an inclusion of your images directory. The build element would look like the following:

<project>
    [...]
    <build>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
                <excludes>
                    <exclude>images/**</exclude>
                </excludes>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>images/**</include>
                </includes>
            </resource>
        </resources>
    </build>
    [...]
</project>

Thank you for requesting a Maestro evaluation! This is our passion, and we want you to be successful. Please let us know how we may help!

Please enter your name, company email address and phone, and we will send you a link to your pre-built hosted evaluation within minutes.






I have read and agree to the Terms and Conditions.