Maven Change a value in a file based on profile - maven-2

I have a properties file called ApplicationResources.properties in my application with a property that changes depending on the environment. Let us say the property is:
resources.location=/home/username/resources
and this value is different when the application is executed during development and when the application goes into production.
I know that I can use different profiles in Maven to perform different build tasks in different environments. What I want to do is somehow replace the value of the resources.location in the properties file based on the Maven profile in use. Is this even possible?

What I want to do is somehow replace the value of the resources.location in the properties file based on the Maven profile in use. Is this even possible?
Yes it is. Activate resources filtering and define the value to replace in each profile.
In your ApplicationResources.properties, declare a token to replace like this:
resources.location=${your.location}
In your POM, add a <filtering> tag for the appropriate <resource> and set it to true like this:
<project>
...
<build>
...
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
...
</resources>
...
</build>
...
</project>
Then, add a <your.location> element within the <properties> element inside each profile:
<project>
...
<profiles>
<profile>
<id>my-profile</id>
...
<properties>
<your.location>/home/username/resources</your.location>
</properties>
...
</profile>
...
</profiles>
</project>
More on filtering of resources here and here.

Related

How to exclude a module from a Maven reactor build?

We have a Maven 2 project with lots of modules in it. Example:
<modules>
<module>common</module>
<module>foo</module>
<module>data</module>
<module>bar</module>
... more ...
</module>
Let's say the "data" module is time consuming to build and we want to exclude it when the project is build by a CI server. Currently we use two pom.xml files to achieve this. One has all modules in it and the other one has all modules except the ones which can be left out for CI. But that's pretty annoying because sometimes we forget to put a new module into both files.
Is there a solution which doesn't need two separate module lists?
With Maven 3.2.1, you can now use -pl !<module_name>,!<module_name> to exclude certain modules from the reactor build.
See this feature request: https://issues.apache.org/jira/browse/MNG-5230
The easiest might be to use profiles like this:
<project>
...
<modules>
<module>common</module>
<module>foo</module>
<module>bar</module>
<modules>
...
<profiles>
<profile>
<id>expensive-modules-to-build</id>
<modules>
<module>data</module>
</modules>
</profile>
</profiles>
</project>
You should then check out ways you can activate profiles
The projects to build can also be specified on the mvn command line. This would remove the need for a separate pom, but instead you would have to change the CI configuration everytime there is a new module.
-pl,--projects <arg> Comma-delimited list of specified
reactor projects to build instead
of all projects. A project can be
specified by [groupId]:artifactId
or by its relative path.
Maybe a combination of this flag and --also-make-dependents or --also-make would reduce this maintenance burden again.
-am,--also-make If project list is specified, also
build projects required by the
list
-amd,--also-make-dependents If project list is specified, also
build projects that depend on
projects on the list
I assume you want the default build to always build everything, regardless of speed, so that new developers can get started quickly without having to understand lots about the POM. You can use profiles like this:
<modules>
<module>common</module>
<module>foo</module>
<module>bar</module>
</modules>
...
<profiles>
<profile>
<id>expensive-modules-to-build</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<modules>
<module>data</module>
</modules>
</profile>
</profiles>
</project>
The problem with this is that if a developer specifies another profile on the command line, then the expensive-modules-to-build isn't included (unless the developer also specifies it). This makes it complicated to remember which profiles need to be included.
Here is a hacky way around that. Both profiles are always included, because the pom.xml file always exists. So to exclude the expensive modules, you can use -P!full-build on the command line.
<profiles>
<profile>
<id>full-build</id>
<activation>
<file>
<exists>pom.xml</exists>
</file>
</activation>
<modules>
<module>data</module>
</modules>
</profile>
<profile>
<id>short-build</id>
<activation>
<file>
<exists>pom.xml</exists>
</file>
</activation>
<modules>
<module>common</module>
<module>foo</module>
<module>bar</module>
</modules>
</profile>
</profiles>
Another idea: Reactor modules can be nested, so it should be possible to group your fast and slow-building modules into separate poms and then add another aggregator pom containing these two as modules. Your CI Server could then only reference the pom containing the fast building modules.
<artifactId>fast</artifactId>
<modules>
<module>fast-a</module>
<module>fast-b</module>
<module>fast-c</module>
</module>
<artifactId>all</artifactId>
<modules>
<module>fast</module>
<module>slow</module>
</module>
You could be to use maven profiles. In our build environment, we created a profile quick that disables many plugins and test execution.
This is done by
<profile>
<id>quick</id>
<properties>
<skipTests>true</skipTests>
<!-- others... -->
</properties>
<build>
<plugins>
<!-- configuration... -->
</plugins>
</build>
</profile>
And then we invoke maven the following way
mvn groupId:artifactId:goal -P quick
You could maybe disable compilation and other standard plugins in the pom of your module to speed it up.
Not exactly the answer these folks were asking for. My situation was I wanted to deploy only the parent pom. I'm using the spring-boot-thin-layout in a child module. This requires the parent module be deployed into artifactory. I added the following into my project. It enables skipping of install and/or deploy phase.
In my parent pom:
<properties>
<disable.install>true</disable.install>
<disable.deploy>true</disable.deploy>
<enable.deployAtEnd>true</enable.deployAtEnd>
</properties>
<profiles>
<profile>
<id>deploy-parent</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<disable.install>true</disable.install>
<disable.deploy>true</disable.deploy>
<deployAtEnd>${enable.deployAtEnd}</deployAtEnd>
</properties>
<build>
<finalName>${project.version}</finalName>
</build>
</profile>
</profiles>
And the in my child pom(s) or any module you don't want deployed with parent:
<properties>
<maven.install.skip>${disable.install}</maven.install.skip>
<maven.deploy.skip>${disable.deploy}</maven.deploy.skip>
<deployAtEnd>${enable.deployAtEnd}</deployAtEnd>
</properties>
So effectively when I run mvn deploy on the parent pom, it will compile all the modules, not run install on anything, and then at the end deploy any module not having <maven.deploy.skip>${disable.deploy}</maven.deploy.skip> in it's properties. So in my case only deploying the parent.

Maven profiles and install

If I have Maven builds set up for an app with profiles set up for different environments (say like prod vs. dev, defining different DB settings and stuff like that) the 'install' goal doesn't seem to make sense, as I don't know which environment got installed into my repo - I've just got com.example.myproject:myapp:0.0.1.
Have I misunderstood something, or are profiles supposed to be used with other goals?
Well, you could use the classifier attribute so that each profile creates a jar with the classifier, i.e. a unique jar for each environment. Here is a code snippet to illustrate this. When run with the dev profile (mvn -P dev install), it creates a jar with -dev classifier, like myapp-dev-0.0.1.jar
<project>
...
<properties>
<env></env>
</properties>
...
<build>
<plugins>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<classifier>${env}</classifier>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
...
<profile>
<id>dev</id>
<properties>
<env>dev</env>
</properties>
...
</profile>
</profiles>
</project>
You run the usual mvn commands and can select the appropriate profile with -P http://maven.apache.org/guides/introduction/introduction-to-profiles.html So it dependends on which profile you chose, what gets installed in the repository.

Using maven using non standard directory layout

I am trying to apply maven to an existing project which already has a directory structure in place. All I can find from previous question is the following.
Maven directory structure
However, my requirement is more detailed. Please see below for the directory structure:
<root dir>
|
+--src-java
|
+--src-properties
|
+--WEB-INF
I know we could have something like
<build>
<sourceDirectory>src-java</sourceDirectory>
...
</build>
But sourceDirectory is for JAVA source code only, if I'm not mistaken.
For the above structure, how do I declare it in pom.xml? Moving the directory is my last option right now.
I guess you need to have something similar to below.
Seeing WEB-INF, I assume you want to build a war. Maven war plugin does this. You will need to configure this a bit since the folder structure is non-standard - for instance you may need to specify the location of web.xml using webXml property. These are documented in the usage page.
<build>
<sourceDirectory>src-java</sourceDirectory>
...
<resources>
<resource>
<directory>src-properties</directory>
</resource>
</resources>
...
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<warSourceDirectory>WEB-INF</warSourceDirectory>
...
</configuration>
</plugin>
</plugins>
</build>
You can change the default directory structure declared in the Super POM by overwriting them in your pom.
For your example, e.g.
<sourceDirectory>src-java</sourceDirectory>
<resources>
<resource>
<directory>src-properties</directory>
</resource>
</resources>
Maven will copy all resources to the jar file. If you want to include WEB-INF to the jar it would be best to move it into the specified resource directory. Otherwise you have to copy it by your own (with maven plugins) to the target directory - I suppose.
<resources>
<resource>
<directory>${project.basedir}/src/main/resources</directory>
</resource>
From here.

How can I change a .properties file in maven depending on my profile?

How can I change a .properties file in maven depending on my profile? Depending on whether the application is built to run on a workstation or the datacenter parts of the file my_config.properties change (but not all).
Currently I manually change the .properties file within the .war file after hudson builds each version.
As often, there are several ways to implement this kind of things. But most of them are variations around the same features: profiles and filtering. I'll show the most simple approach.
First, enable filtering of resources:
<project>
...
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
...
</build>
</project>
Then, declare a place holder in your src/main/resources/my_config.properties, for example:
myprop1 = somevalue
myprop2 = ${foo.bar}
Finally, declare properties and their values in a profile:
<project>
...
<profiles>
<profile>
<id>env-dev</id>
<activation>
<property>
<name>env</name>
<value>dev</value>
</property>
</activation>
<properties>
<foo.bar>othervalue</foo.bar>
</properties>
</profile>
...
</profiles>
</project>
And run maven with a given profile:
$ mvn process-resources -Denv=dev
[INFO] Scanning for projects...
...
$ cat target/classes/my_config.properties
myprop1 = somevalue
myprop2 = othervalue
As I said, there are variation around this approach (e.g. you can place values to filter in files), but this will get you started.
References
Introduction to Build Profiles
Maven Resources Filtering
More resources
A Maven2 multi-environment filter setup
Maven project filtering
Using Maven profiles and resource filtering
Building For Different Environments with Maven 2

Maven Profile - Activate Profile depending on packaging

I have a POM which declares web application stuff that is common to my projects. I use this as the parent for all web applications.
Is it possible to activate a profile only when the packaging is war? I have tried the property approach, but that doesn't work (as it isn't a system/environment property).
Since this fails the build, I can simply disable that profile when installing the POM, but I'd like it to be more intelligent on its own.
Walter
You can simply check the existence of src/main/webapp. Each web application that uses the Maven standard directory layout should contain this folder. So you avoid unnecessary dummy files.
<profile>
<id>custom-profile-eclipse-project-generation-webapp</id>
<activation>
<file>
<exists>${basedir}/src/main/webapp</exists>
</file>
</activation>
<build>
</build>
</profile>
More precise you can also check for the the existence of ${basedir}/src/main/webapp/WEB-INF/web.xml. That should definitively identify a war-project.
For myself I use this configuration in my common super-pom to configure the maven-eclipse-plugin for different project types. Thats very handy to get homogenous eclipse-configurations over the same project type in our organization, especially when developers straightforwardly run eclipse:eclipse on multi-module-projects.
I know this isn't answering your question directly, but the usual workaround for problems like this is to just use specialization (as with classes).
So you have your MasterPom with all common behavior.
MasterWarPom that extends MasterPom (is it's parent), and put any 'packing is war' specializations in here.
Likewise you could have MasterJarPom, etc ...
That way the differences are split out nicely.
There's no clean way to do that, the parent module has no way of knowing the child's packaging. (Non-clean solutions would involve creating a plugin that parses the child module's pom etc.)
The best I've been able to come up with for these sorts scenarios has been to use a file-based activation trigger.
eg my parent pom has
<profile>
<id>maven-war-project</id>
<activation>
<file><!-- add a file named .maven-war-project-marker to webapp projects to activate this profile -->
<exists>${basedir}/.maven-war-project-marker</exists>
</file>
</activation>
<build>
<plugins>
<!-- configuration for webapp plugins here -->
</plugins>
</build>
and webapp projects that inherit from this parent contain a file named
'.maven-war-project-marker'
that activates the profile
This looks pretty obtuse but works fairly reliably whereas
- using property-activation is unreliable if a different person or system does the build,
- inheriting from type-specific parents became a bit cumbersome for me as the grandparent-pom changes version relatively frequently as it is used to define 'standard' or preferred versions of common dependencies which in turn required corresponding releases of all of the type-specific parents with no change other than the grandparent version
Try in this way ?
mvn package -Dmaven.test.skip=true -Dwar
<project ×××××>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>××××</groupId>
<artifactId>×××××</artifactId>
<version>×××××</version>
<relativePath>../../</relativePath>
</parent>
<artifactId>×××××</artifactId>
<name>${project.artifactId}-${project.version}</name>
<description>${project.artifactId}-${project.version}</description>
<properties>
<packaging.type>jar</packaging.type>
</properties>
<profiles>
<profile>
<activation>
<property>
<name>war</name>
</property>
</activation>
<properties>
<packaging.type>war</packaging.type>
</properties>
<build>
<finalName>ROOT</finalName>
</build>
</profile>
</profiles>
<packaging>${packaging.type}</packaging>
<dependencies>
<dependency>
... ...
</dependency>
... ...
</dependencies>