Maven filtering resources - maven

I am running a simple maven project (maven version 3.3.9) with profiles and filtering on resources. It seems like the filtering is done always on the default profile.
There is 2 configuration files in src/main/filters (default) : config-dev.properties and config-prod.properties which contains only one variable
application.env=development
application.env=production
And a resource file in src/main/resources (default) with this content :
We are working on ${application.env}
Command line used is
mvn clean resources:resources -Pprod
The expected output is
We are working on production
But the filtered resource file contains
We are working on development
Maven pom snippet looks like:
<build>
<finalName>test-maven-module</finalName>
<filters>
<filter>src/main/filters/config-${build.profile.id}.properties</filter>
</filters>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
and profiles configuration
<profiles>
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<build.profile.id>dev</build.profile.id>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<build.profile.id>prod</build.profile.id>
</properties>
</profile>
</profiles>
Any suggestion?

I found the solution on the post Eclipse + maven : profile ignored
The issue was with the use of the "refresh using native hooks or polling" option ( preferences > general > workspace > refresh using native hooks ). Unchecking this option resolves the problem.

Related

Providing external arguments to Maven pom and replace same in application.properties file

I am working on testNg project where I need to provide external arguments to the pom.xml which should get replaced in application.properties file which further will be used in my project.
Could anyone list out the steps and plugins i need to use.
I have resolved the issue. I have added a profile in pom.xml and configuration for property substitution.
<profiles>
<profile>
<id>profile1</id>
<properties>
<url>https://www.bing.com</url>
<search>bitcoin</search>
</properties>
</profile>
</profiles>
<build>
<testOutputDirectory>${basedir}/target/classes</testOutputDirectory>
<filters>
<filter>src/main/resources/runtime.properties</filter>
</filters>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
runtime.properties
url=${url}
search=${search}
To Run the test:
mvn test -Pprofile1 -Durl=https://www.google.com -Dsearch=Blockchain
The value of url and search variable will be replaced in runtime.properties file by the value given in arguments of the above command .
-Durl=https://www.google.com and
-Dsearch=Blockchain

Can Maven ask the user for values and enter them into a file?

I have a lot of config files that values have to change in. I would like to know if someone runs the "package" command can it ask for some values and insert them into my project files?
Better Approach would be have different property/config file depending upon environment.
Prod
Dev
Keep the two set of values in two different file. At times specify the file name.
For 90% of build tasks, there's Maven. For everything else, there's maven-antrun-plugin.
I suggest creating a custom ant script (which can be embedded in your pom.xml) that prompts for user input and writes out your config files using the Ant Input Task
You can use maven -P to select a maven profile and in turn selec the property files for it.
<profiles>
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<resource.prefix>dev</resource.prefix>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<resource.prefix>prod</resource.prefix>
</properties>
</profile>
</profiles>
Now access your resource file as ${resource.prefix}_config.properties. So when the profile is prod, the resource file prod_config.properties will be taken.
You cannot really make maven prompt for input unless you do some ant stuff suggested by noahz.
What you can do if you don't want to play around with Profiles is to use properties in your pom file.
Example:
<project>
<groupId>abc</groupId>
<artifactId>def</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<myProperty>someValue</myProperty>
</properties>
<build>
<plugins>
<plugin>
...
<configuration>
<outputDir>${myProperty}</outputDir>
</configuration>
</plugin>
</plugins>
</build>
</project>
You can use the property wherever you want within the pom file and you can even use the property when filtering resources.
The property could be empty by default and then have a new value set from command line:
mvn package -DmyProperty=anotherValue
And the anotherValue would be propagated to wherever it is used in pom.
You can read about Maven Resource Filtering here.
If you place a file in src/main/resources it could be filtered with the above property:
src/main/resources/important-stuff.properties
some.nice.property = Nice!
some.variable.property = ${myProperty}
And this should be added to the pom:
<build>
...
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
...
</build>
The filtered important-stuff.properties would end up in target/classes and in the jar and look like this:
some.nice.property = Nice!
some.variable.property = anotherValue
Resource filtering is really handy.

maven3 detect maven version for plugin - fails to activate other default profiles

I have a need to detect if a user is using mvn2 or mvn3 in my parent pom in order to load the proper plugin version. I followed the recommendation from here : http://maven.apache.org/plugins/maven-site-plugin/maven-3.html#Using_maven-site-plugin_2.x_with_Maven_2_and_maven-site-plugin_3.x_with_Maven_3
The detection mechanism works great - however, my other profiles that are activatedByDefaul do not get picked up anymore.
Super pom look like below:
<profile>
<id>profile-1</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<id>profile-2</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
</profile>
<profile>
<id>maven-3</id>
<activation>
<file>
<!-- This employs that the basedir expression is only recognized by Maven 3.x (see MNG-2363) -->
<exists>${basedir}</exists>
</file>
</activation>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>com.company.plugins</groupId>
<artifactId>my-super-plugin</artifactId>
<version>1.0-123</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</profile>
</profiles>
when I run mvn help:active-profiles with mvn3 --> only maven-3 profile get listed. If I use mvn2, profile-1 is rightfully listed.
*Edit * : as it turns out, its actually well documented here : http://maven.apache.org/guides/introduction/introduction-to-profiles.html
This profile will automatically be active for all builds unless another profile in the same POM is activated using one of the previously described methods. All profiles that are active by default are automatically deactivated when a profile in the POM is activated on the command line or through its activation config.
My question is now then : what work around would you recommend to have profile1 activated by default and profile 2 activated if -P profile2, while maven-3 profile activated if maven3 is used?
So far I haven't found anything better than just:
<activation>
<property>
<name>!dummy</name>
</property>
</activation>
where dummy is some kind of stupid variable name that you won't use for sure.

How to configure maven to use different log4j.properties files in different environments

I want to be able to use different log4j configuration for different environments.
In my development environment, I want to use log4j.properties (A). But when I build in Maven for the production environment, I want to use log4j.properties (B).
Please tell me how to configure this in my pom.xml?
You can use profiles to achieve the desired behavior:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.5</version>
<executions>
<execution>
<id>log4j</id>
<phase>process-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>output_directory</outputDirectory>
<resources>
<resource>${log4j.file}</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<log4j.file>path_to_file_A</log4j.file>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<log4j.file>path_to_file_B</log4j.file>
</properties>
</profile>
</profiles>
1. in your project add 3 folders :
Your Project\src\main\resources\
\A > log4j.properties
\B > log4j.properties
\Default > log4j.properties
2. in pom.xml
<properties>
<param>Default</param>
</properties>
<build>
<resources>
<resource>
<directory>src/main/resources/${param}</directory>
</resource>
</resources>
</build>
3.
- if : mvn clean install : classpath => log4j.properties(Default)
- if : mvn clean install -Dparam=A : classpath => log4j.properties(A)
- if : mvn clean install -Dparam=B : classpath => log4j.properties(B)
> much better than using profiles is more extensible without touching the pom
You don't need the maven-resources-plugin if you have a simple environment.
In this example, log4j.properties B is the file you use for production and is in the directory src/main/java and log4j.properties A is the file you use for development and is in the directory /Users/junger/.m2/.
In your pom.xml:
<properties>
<log4j.properties.directory>src/main/java</log4j.properties.directory>
</properties>
<build>
<resources>
<resource>
<directory>${log4j.properties.directory}</directory>
<includes>
<include>log4j.properties</include>
</includes>
</resource>
</resources>
</build>
Now, in your /Users/junger/.m2/settings.xml (create one if it doesn't exist):
<profiles>
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<log4j.properties.directory>/Users/devuser/.m2/</log4j.properties.directory>
</properties>
</profile>
</profile>
By using this method, each developer can have a different log4j.properties directory and you keep your pom.xml clean.
Simplest way for me,
Define a system variable ENV and set its value _dev for your development env.
Where you refer this file use like this log4j${ENV}.properties
So,
In production it simply use log4j.xml and for your dev log4j_dev.xml
In order to prevent problems it would be better to create also ENV variable for production as _pro so for production log4j_pro.xml, for dev log4j_dev.xml will be used.
I believe that relying on different files than copying resource is better practice.
There is a very simple solution good for small projects with jar packaging (I haven't tested it on war packaged projects). The only disadvantage is that you have to duplicate all resources, but if your only resource is log4j.properties this is not a problem.
If you have a directory tree like this:
...
You should have the following pom:
<build>
<finalName>${project.artifactId}</finalName>
<sourceDirectory>src/</sourceDirectory>
<resources>
<resource>
<directory>${resources.path}</directory>
</resource>
</resources>
</build>
<profiles>
<profile>
<id>default</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<resources.path>resources/prod</resources.path>
</properties>
</profile>
<profile>
<id>dev</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<properties>
<resources.path>resources/dev</resources.path>
</properties>
</profile>
</profiles>
Then when you use dev profile log4j.properties from resources/dev is used. When you use any other profile or no profile at all then log4j.properties from resources/prod is used. So your *.jar should look like this:
Of course if you have different resources location, for example main/java/resources/..., you should specify it instead of resources/...
To some extent you can reference environment variables inside a log4j.properties to add environment dependent behavior.
e.g.
log4j.rootLogger=${rootLoggerLevel}, ${appender}

maven super pom's profile properties inheritance at child poms

at my project there is 2 profiles and each profile has one property.
But I could not use master's properties at child's resources.
Here is described clearly but it seems that there is only one pom file and the sample shown at there is not an multi-module maven project.
All I want to do is use this properties at spring level like changing the location of properties file.
<profile>
<id>p1</id>
<properties>
<properties.location>file:/apps-core1.properties</properties.location>
</properties>
</profile>
<profile>
<profile>
<id>p2</id>
<properties>
<properties.location>file:/apps-core2.properties</properties.location>
</properties>
</profile>
<profile>
and I want to use "properties.location" at every pom file I had, either main-resources or test-resources.
here is the spring usage
<context:property-placeholder location="\${properties.location}" />
i got it working with a multi-module project with:
parent pom with <modules /> config and your profiles
module pom with following config
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>
see maven resources and filtering

Resources