Maven: The Complete Reference

9.3. Resource Filtering

You can use Maven to perform variable replacement on project resources. When resource filtering is activated, Maven will scan resources for property references surrounded by ${ and }. When it finds these references it will replace them with the appropriate value in much the same way the properties defined in the previous section can be referenced from a POM. This feature is especially helpful when you need to parameterize a build with different configuration values depending on the target deployment platform.

Often a .properties file or an XML document in src/main/resources will contain a reference to an external resource such as a database or a network location which needs to be configured differently depending on the target deployment environment. For example, a system which reads data from a database has an XML document which contains the JDBC URL along with credentials for the database. If you need to use a different database in development and a different database in production. You can either use a technology like JNDI to externalize the configuration from the application in an application server, or you can create a build which knows how to replace variables with different values depending on the target platform.

Using Maven resource filtering you can reference Maven properties and then use Maven profiles to define different configuration values for different target deployment environments. To illustrate this feature, assume that you have a project which uses the Spring Framework to configure a BasicDataSource from the Commons DBCP project. Your project may contain a file in src/main/resources named applicationContext.xml which contains the XML listed in Referencing Maven Properties from a Resource.

Referencing Maven Properties from a Resource. 

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

    <bean id="someDao" class="com.example.SomeDao">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <bean id="dataSource" destroy-method="close"
          class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
</beans>

Your program would read this file at runtime, and your build is going to replace the references to properties like jdbc.url and jdbc.username with the values you defined in your pom.xml. Resource filtering is disabled by default to prevent any unintentional resource filtering. To turn on resource filtering, you need to use the resources child element of the build element in a POM. Defining Variables and Activating Resource Filtering shows a POM which defines the variables referenced in Referencing Maven Properties from a Resource and which activates resource filtering for every resource under src/main/resources.

Defining Variables and Activating Resource Filtering. 

<project>
    ...
    <properties>
        <jdbc.driverClassName>
            com.mysql.jdbc.Driver</jdbc.driverClassName>
        <jdbc.url>jdbc:mysql://localhost:3306/development_db</jdbc.url>
        <jdbc.username>dev_user</jdbc.username>
        <jdbc.password>s3cr3tw0rd</jdbc.password>
    </properties>
    ...
    <build>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
            </resource>
        </resources>
    </build>
    ...
    <profiles>
        <profile>
            <id>production</id>
            <properties>
                <jdbc.driverClassName>oracle.jdbc.driver.OracleDriver</jdbc.driverClassName>
                <jdbc.url>jdbc:oracle:thin:@proddb01:1521:PROD</jdbc.url>
                <jdbc.username>prod_user</jdbc.username>
                <jdbc.password>s00p3rs3cr3t</jdbc.password>
            </properties>
        </profile>
    </profiles>
</project>

The four variables are defined in the properties element, and resource filtering is activated for resources under src/main/resources. Resource filtering is deactivated by default, and to activate it you must explicitly set filtering to true for the resources stored in your project. Filtering is deactivated by default to prevent accidental, unintentional filtering during your build. If you build a project with the resource from Referencing Maven Properties from a Resource and the POM from Defining Variables and Activating Resource Filtering and if you list the contents of the resource in target/classes, you should see that it contains the filtered resource:

$ mvn install
...
$ cat target/classes/applicationContext.xml
...
<bean id="dataSource" destroy-method="close"
      class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:3306/development_db"/>
    <property name="username" value="dev_user"/>
    <property name="password" value="s3cr3tw0rd"/>
</bean>
...

The POM in Defining Variables and Activating Resource Filtering also defines a production profile under the profiles/profile element which overrides the default properties with values that would be appropriate for a production environment. In this particular POM, the default values for the database connection are for a local MySQL database installed on a developer’s machine. When the project is built with the production profile activated, Maven will configure the system to connect to a production Oracle database using a different driver class, URL, username, and password. If you build a project with the resource from Referencing Maven Properties from a Resource and the POM from Defining Variables and Activating Resource Filtering with the production profile activated and if you list the contents of the resource in target/classes, you should see that it contains the filtered resource with production values:

$ mvn -Pproduction install
...
$ cat target/classes/applicationContext.xml
...
<bean id="dataSource" destroy-method="close"
      class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName"
              value="oracle.jdbc.driver.OracleDriver"/>
    <property name="url" value="jdbc:oracle:thin:@proddb01:1521:PROD"/>
    <property name="username" value="prod_user"/>
    <property name="password" value="s00p3rs3cr3t"/>
</bean>
...