Maven web resource filtering SNAPSHOT version - maven

Using Maven, I'd like to update a parameter in a file to either "true" or "false" based on if the version number is a SNAPSHOT or not. Currently I use the maven-war-plugin to update some other properties based on Maven properties. I've tried to use the maven properties along with the maven-release-plugin, but this seems to not work:
Maven pom.xml:
<project>
...
<properties>
<someProperty>value</somePropery>
<isSnapshot>true</isSnapshot>
</properties>
<profiles>
<profile>
<id>release</id>
<properties>
<isSnapshot>false</isSnapshot>
</properties>
</profile>
</profiles>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<configuration>
<webResources>
<resource>
<directory>src/main/webapp</directory>
<filtering>true</filtering>
</resource>
</webResources>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.5.3</version>
<configuration>
<releaseProfiles>release</releaseProfiles>
</configuration>
</plugin>
</plugins>
</build>
</project>
Running a mvn release:prepare and mvn release:perform seems to ignore the overridden property in the final war. This seems to stem from the fact that the release profile is active during the release:perform phase, but not the release:prepare phase when the war is actually built.
Is there a better way to do this or am I missing something?
Edit:
I am running this release from a project pom, which this war pom is a submodule.

Related

Does Maven support multiple variants?

I have a pom for multiple clients, the client specific code is in com.foo.custom. So, for customer A there are classes in com.foo.custom.customerA, for customer B some classes in com.foo.custom.customerB etc. The set of classes in com.foo.custom.customerA is different from those in com.foo.custom.customerB.
When I do mvn package, the code for all the customers shows up in the jar, as expected. Is there a way of selecting just one customer, e.g. mvn package -Dcust=customerB, and then have that one customer in the package and the others not?
You can construct a multi-module project with modules like
common
customerA
customerB
...
The customerX modules use common as dependency.
Here is a pratical solution:
pom.xml fragment
<profiles>
<profile>
<id>ncustomerA</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<includes>
<include>src/main/java/customerA/*</include>
</includes>
</configuration>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>ncustomerB</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<includes>
<include>src/main/java/customerA
B/*</include>
</includes>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles
Build commands
mvn package -P customerA
mvn package -P customerB
Here https://maven.apache.org/plugins/maven-jar-plugin/examples/include-exclude.html further information.

Why is my target not getting executed?

I am trying to get ready for deployment and therefore I want to copy the correct configuration files to WEB-INF/classes/ before everything gets packed into the WAR file for either deployment or development.
In the end I want to execute deployment-tasks whenever I call
mvn glcoud:deploy
- which is when I need deployment configuration files - and development-tasks whenever something else gets executed in my project directory.
At the moment I have not decided how exactly I'm going to do it but first of all I try to execute such a "dummy task". Unfortunately it is not working.
This is the profile I configured in the pom.xml:
<profile>
<id>default-profile</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<id>compile</id>
<phase>compile</phase>
<configuration>
<target>
<echo message="Hello World!"/>
<copy file="src/main/resource/x.xml" todir="src/main" />
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>
</profile>
It is supposed to echo "Hello World!" and copy a x.xml file from A to B. I decided to do this in the compile phase which means
mvn clean compile
should actually be enough to get the target executed but .. I wouldn't be here if it worked.
Question: Does somebody know why this is not getting executed?
As mentioned in a comment, I could/should remove pluginManagement from build. However, this would give me an error saying:
Plugin execution not covered by lifecycle configuration: org.apache.maven.plugins:maven-antrun-plugin:1.8:run (execution: compile, phase: compile)
I've added pluginManagement according to an answer of the question "How to solve “Plugin execution not covered by lifecycle configuration” for Spring Data Maven Builds".
The solution below is giving the same “Plugin execution not covered by lifecycle configuration” error
<profile>
<id>default-profile</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<!-- -->
</executions>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
</plugin>
</plugins>
</build>
</profile>
and I am seeing the same for:
<build>
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>default-profile</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<!-- -->
</plugin>
</plugins>
</pluginManagement>
</build>
</profile>
<profiles>
In order to make m2e happy and yet being able to meet your requirements, try the following:
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<id>compile</id>
<phase>compile</phase>
<configuration>
<target>
<echo message="Hello World!"/>
<copy file="src/main/resource/x.xml" todir="src/main" />
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
</plugin>
</plugins>
</build>
Note the additional plugins section which is basically just repeating the artifactId of the plugin.
What's happening here:
Via the pluginManagement section we are telling Maven: whenever the build (via POM configuration or command line execution) needs to execute this plugin, then apply this version by default and this configuration an executions
The m2e not-so-perfect integration between Maven and Eclipse will then be happy about this plugin configuration, however no plugin execution will ever happen unless we effectively declare it
Via the plugins section we are eventually really defining our build, telling Maven to add this plugin to its build plan. No need to specify version, configuration or executions, since we already defined them into the pluginManagement (that is, management of plugins), which will be applied as default configuration/behavior.
For further details concerning the difference between plugins and pluginManagement, check the reference post on SO: Maven: what is pluginManagement.
Further note on the associated phase for such an execution: the prepare-package phase would be a more (semantically correct and maintenability-friendly) choice than compile. Check the official Build Lifecycle phases list for more details. Concerning prepare-package:
perform any operations necessary to prepare a package before the actual packaging.
Update
It appears that not only as described above the prepare-package phase would be a better choice, but it also the right phase to make the m2e plugin perfectly happy in this case.
See POM Reference, Plugin Management:
pluginManagement
However, this only configures plugins that are actually referenced within the plugins element in the children.
That means declaring a plugin in <pluginManagement> is just half of the story. You have to declare it in a <build>/<plugins> section, too, to actually execute its goal.
In your case:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
</plugin>
</plugins>
</build>

Maven overrides configuration in profiles plugin

I have a 3 maven profiles with plugins:
<profile>
<id>first</id>
<build>
<plugins>
<plugin>
...
<configuration>
<var>1</var>
</configuration>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>second</id>
<build>
<plugins>
<plugin>
...
<configuration>
<var>2</var>
</configuration>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>third</id>
<build>
<plugins>
<plugin>
...
<configuration>
<var>3</var>
</configuration>
</plugin>
</plugins>
</build>
</profile>
When i start my build with mvn clean install -P first,second,third -X, I discovered that all this plugins was executed with configuration from from third profile. Is there any way to preserve my configuration for each of my plugins and not to be overriden by third configuration?
As discussed in comments section, You would have to invoke 3 build activating each profile differently
for example
mvn clean install -Pfirst
mvn clean install -Psecond
mvn clean install -Pthird
and to disable compilation in second and third, you could configure maven-compiler-plugin for these profiles and use skipMain property to disable main's source compilation, also for tests

Maven tests run twice when a profile identifier is in multiple projects. Why?

I have numerous projects in IntelliJ, each of which has a pom.xml, and each of the projects' poms inherit from the master pom.xml. One profile (called test1) is present in two of the poms (for project2 and project4). When I run maven from the command line, specifying one project and the profile name, it works (the tests in that project are executed once) Here is the commmand:
mvn test -pl project2 -am -P test1
When I specify both projects (both of which have the same profile present), the tests in project4 are executed twice. Here is the command:
mvn test -pl project2,project4 -am -P test1
I would like the tests only to be executed once. I am running maven 3.1.1.
As a further complication, when I specify just project4, the tests in project2 get executed once, and the tests in project4 don't get executed at all. Here is the command:
mvn test -pl project4 -am -P test1
Here is pom.xml for project2:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns stuff...>
<parent>
<artifactId>parent artifact id</artifactId>
<groupId>group id</groupId>
<version>version</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<name>project2</name>
<artifactId>project2</artifactId>
<packaging>jar</packaging>
<profiles>
<profile>
<id>test1</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.9</version>
<executions>
<execution>
<id>execute-tests-1</id>
<phase>test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<skip>false</skip>
<excludes>
<exclude>com/path/to/exclude/**/*.java</exclude>
</excludes>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<build>
<plugins>
<!-- We don't want to run any tests without an active profile -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.9</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<!-- This exports the classes in the tests for use with our other modules' tests -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
[ dependencies ...]
</dependencies>
</project>
Here is the pom.xml for project4:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns stuff>
<parent>
<artifactId>[parent artifact id]</artifactId>
<groupId>[group id]</groupId>
<version>[version]</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<name>project4</name>
<artifactId>project4</artifactId>
<packaging>jar</packaging>
<dependencies>
[ dependencies ...]
</dependencies>
<profiles>
<profile>
<id>test1</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.9</version>
<executions>
<execution>
<id>execute-tests-2</id>
<phase>test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<includes>
<include>com/path/to/tests/*.java</include>
</includes>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
[ dependencies...]
</dependencies>
</profile>
</profiles>
</project>
I figured out the answer to my own question (by looking carefully at some of our other projects' Maven test setup). I had to do two things:
Include a <skip>false</skip> element in the <configuration> aggregate in the surefire plugin.
Include a generic surefire <plugins> aggregate outside of the <profiles> section. This one has <skip> set to true and prevents tests being run unless they are in a profile. Here is what the section looks like:
<build>
<plugins>
<!-- We don't want to run any tests without an active profile -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.9</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
The problem was that the tests were running the default-test lifecycle phase and then they were running again in the test phase. After I made the change they only ran in the test phase.

Maven 3 profile with extensions

My question had been addressed in this thread, but the explanation is not clear.
I have this build definition in one of my pom.xml files:
<build>
<finalName>${my.project}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.0</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
<extensions>
<extension>
<groupId>org.kuali.maven.wagons</groupId>
<artifactId>maven-s3-wagon</artifactId>
<version>1.1.19</version>
</extension>
</extensions>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/settings.properties</include>
</includes>
</resource>
</resources>
</build>
Notice that I'm using the maven-s3-wagon extension.
Next, I would like to have 2 different profiles, each with it's own settings, plugins and extensions but maven does not allow the extensions tag under a profile.
When I try using a profile:
<profiles>
<profile>
<id>local-build</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<build>
<finalName>${my.project}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.0</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
<extensions>
<extension>
<groupId>org.kuali.maven.wagons</groupId>
<artifactId>maven-s3-wagon</artifactId>
<version>1.1.19</version>
</extension>
</extensions>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/settings.properties</include>
</includes>
</resource>
</resources>
</build>
</profile>
</profiles>
I get a an error in my pom:
cvc-complex-type.2.4.a: Invalid content was found starting with element 'extensions'. One of '{"http://maven.apache.org/POM/4.0.0":defaultGoal, "http://maven.apache.org/POM/
4.0.0":resources, "http://maven.apache.org/POM/4.0.0":testResources, "http://maven.apache.org/POM/4.0.0":directory, "http://maven.apache.org/POM/4.0.0":filters, "http://
maven.apache.org/POM/4.0.0":pluginManagement}' is expected.
Question So using the extension tag means I can't use profiles? How can I use or change build extensions via profile?
Indeed, the official Maven POM reference is not clear about the possible usage of extensions as part of a Maven profile, since it states you can have a build element within it, but not what of the build section.
However, the official Maven model effectively filters and provides what of the build section you can actually use within a profile section. And indeed extensions is not there.
However, what are Maven extensions? Build/Lifecycle enhancement, but also (and essentially): a library added to the runtime classpath of the Maven build, which participates to the build, but it is not packaged with the final artifact.
Hence, in such a scenario (if you need to have extensions in profile or have a profile to change/add an extension) you could use the following trick:
Have an harmless extension as default extension of your build (where harmless means whatever library which could be part of your build classpath and essentially not affect it at all)
Have properties defining the GAV coordinates (GroupId, ArtifactId, Version) of this extension
Have a profile which overrides these properties with the desired (useful) extension
As an example, given the following sample POM:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.sample</groupId>
<artifactId>project</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<extension.groupId>junit</extension.groupId>
<extension.artifactId>junit</extension.artifactId>
<extension.version>4.11</extension.version>
</properties>
<build>
<extensions>
<extension>
<groupId>${extension.groupId}</groupId>
<artifactId>${extension.artifactId}</artifactId>
<version>${extension.version}</version>
</extension>
</extensions>
</build>
<profiles>
<profile>
<id>customize-extension</id>
<properties>
<extension.groupId>junit</extension.groupId>
<extension.artifactId>junit</extension.artifactId>
<extension.version>4.12</extension.version>
</properties>
</profile>
</profiles>
</project>
The default build (without the customize-extension profile activated), would use the default defined properties and as such add junit as build extension: this is harmless (although it may create conflicts with another junit version of your build, so make sure you use the same version of use an even more harmless library for that).
You can check Maven will pick it up by running a really first build phase, just to check information in our case, and enable the debug flag:
mvn initialize -X
And checking as part of the build log:
[DEBUG] Populating class realm extension>junit:junit:4.11
[DEBUG] Included: junit:junit:jar:4.11
Now let's use our trick: let's add (change) a build extension via profile:
mvn initialize -X -Pcustomize-extension
And as part of our build log we would have:
[DEBUG] Populating class realm extension>junit:junit:4.12
[DEBUG] Included: junit:junit:jar:4.12
Bingo. Maven picked up a different extension (in this case, a different version, the 4.12) and we succeeded on changing (or actually adding a meaningful) build extension via profile.
Just a crazy idea: use modules
Define a parent pom like this:
<groupId>org.example</groupId>
<artifactId>my-parent</artifactId>
<version>1.0</version>
<packaging>pom</packaging>
<profiles>
<profile>
<id>use-pom1</id>
<modules>
<module>pom1</module>
</modules>
</profile>
<profile>
<id>use-pom2</id>
<modules>
<module>pom2</module>
</modules>
</profile>
</profiles>
Define the desired extensions on pom1 and pom2.
I think the solution is here http://maven.apache.org/guides/mini/guide-using-extensions.html
Define a build section where extensions are defined and then into the profile set the attribute true ( like in the second profile shown below )
<build>
<extensions>
<extension>
<groupId>org.apache.maven.wagon</groupId>
<artifactId>wagon-ssh</artifactId>
<version>2.9</version>
</extension>
</extensions>
</build>
<profiles>
<profile>
<id>create-default</id>
<activation>
<activeByDefault>true</activeByDefault>
<property>
<name>build</name>
<value>full</value>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>create-core</id>
<activation>
<property>
<name>build</name>
<value>full</value>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<extensions>true</extensions>
<version>2.6</version>
<configuration>
<finalName>import-station-core-${project.version}</finalName>
</configuration>
<executions>
<execution>
<id>make-jar</id>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>

Resources