maven-replacer-plugin to replace tokens in build and not source

amphibient picture amphibient · Aug 23, 2016 · Viewed 10k times · Source

I am trying to use the maven-replacer-plugin to replace tokens in my web.xml when it is built in the WAR file but not in the source, which would remove the tokens for subsequent builds and show the file as changed relative to the version control repository.

Currently, I am only able to change the file in the source, which does not meet my requirement:

<plugin>
    <groupId>com.google.code.maven-replacer-plugin</groupId>
    <artifactId>replacer</artifactId>
    <version>1.5.2</version>
    <executions>
        <execution>
            <phase>prepare-package</phase>
            <goals>
                <goal>replace</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <file>${project.basedir}/src/main/webapp/WEB-INF/web.xml</file>
        <replacements>
            <replacement>
                <token>@@sec.level@@</token>
                <value>local</value>
            </replacement>
        </replacements>
    </configuration>
</plugin>

Question: How can I run the replacer to only change the file in the WAR package while leaving the source unchanged for subsequent builds?

Answer

A_Di-Matteo picture A_Di-Matteo · Aug 23, 2016

You can use the exploded goal of the maven-war-plugin to get to a temporary folder (like whatever created under target actually) the exploded version of what would later on be part of the final war file, then execute the replacer plugin on this file (a safe copy, not in conflict with other plugins consuming the file).

This approach is actually also documented by the official replacer plugin doc

That is, having a similar configuration:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-war-plugin</artifactId>
    <version>2.6</version>
    <configuration>
        <useCache>true</useCache>
    </configuration>
    <executions>
        <execution>
            <id>prepare-war</id>
            <phase>prepare-package</phase>
            <goals>
                <goal>exploded</goal>
            </goals>
        </execution>
    </executions>
</plugin>

<plugin>
    <groupId>com.google.code.maven-replacer-plugin</groupId>
    <artifactId>replacer</artifactId>
    <version>1.5.2</version>
    <executions>
        <execution>
            <phase>prepare-package</phase>
            <goals>
                <goal>replace</goal>
            </goals> 
        </execution>
    </executions>
    <configuration>
        <file>${project.build.directory}/${project.build.finalName}/WEB-INF/web.xml</file>
        <token>@@sec.level@@</token>
        <value>local</value>
    </configuration>
</plugin>

Note: the replacer documentation also suggests to use the useCache option which should prevent the plugin to override what the exploded goal previously created. However, the option doesn't really suit this purpose.


Similarly, the following approach would instead work according to my tests:

  • Use the exploded goal of the maven-war-plugin to create a temporary copy of the future war file in a <war_name>-tmp directory under target: that's not an issue, whatever is under target is supposed to be discarded via a clean command anyway
  • Configure the replacer plugin to replace that copy of the web.xml file
  • Configure the default war goal using its webXml option to point to that web.xml file for its final war file

The following would apply the approach described above:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-war-plugin</artifactId>
    <version>2.6</version>
    <executions>
        <execution>
            <!-- explode the future war content for pre-package processing -->
            <id>prepare-war</id>
            <phase>prepare-package</phase>
            <goals>
                <goal>exploded</goal>
            </goals>
            <configuration>
                <webappDirectory>${project.build.directory}/${project.build.finalName}-tmp</webappDirectory>
            </configuration>
        </execution>
        <execution>
            <!-- use the same execution id to further configure the default binding and execution -->
            <id>default-war</id>
            <phase>package</phase>
            <goals>
                <goal>war</goal>
            </goals>
            <configuration>
                <!-- during the package phase, use the processed web.xml file -->
                <webXml>${project.build.directory}/${project.build.finalName}-tmp/WEB-INF/web.xml</webXml>
            </configuration>
        </execution>
    </executions>
</plugin>

<plugin>
    <groupId>com.google.code.maven-replacer-plugin</groupId>
    <artifactId>replacer</artifactId>
    <version>1.5.2</version>
    <executions>
        <execution>
            <!-- apply pre-package processing on web resources -->
            <id>process-web-resources</id>
            <phase>prepare-package</phase>
            <goals>
                <goal>replace</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <file>${project.build.directory}/${project.build.finalName}-tmp/WEB-INF/web.xml</file>
        <token>@@test@@</token>
        <value>local</value>
    </configuration>
</plugin>