In maven, how to override plugin configuration in settings.xml - maven

I want to override a particular plugin configuration that's defined in the pom.xml. I don't want to modify the pom.xml for various reasons. Is there a way to define a config attribute for that plugin in settings.xml that override corresponding pom.xml plugin config?
In the below example, you'll notice that the plugin xx-plugin is defined in profile1 in pom.xml. In my settings.xml I've already defined profile2 to override property prop1 from pom.xml. But how to override config3. I apologize if this is a silly question. I am a little new to maven.
This is what my pom.xml looks like:
<profile>
<id>profile1</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<build>
<plugins>
<plugin>
<groupId>com.xx.yyy</groupId>
<artifactId>xx-plugin</artifactId>
<executions>
<execution>
<id>xx-install</id>
<phase>install</phase>
<goals>
<goal>xx-install</goal>
</goals>
<configuration>
<config1>AAA</config1>
<config2>BBB</config2>
<config3>CCC</config3> <!-- I want to override this with value DDD -->
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
This is what my settings.xml looks like:
<profile>
<id>profile2</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<prop1>overriden-value</prop1> <!-- This works -->
</properties>
<!-- Somehow override config3 here -->
<!-- <config3>DDD</config3> -->
</profile>

AFAIK you can only override properties with settings.xml profiles. You'd have to change your plugin's configuration to use a property instead of a fixed value:
<!-- define your property -->
<properties>
<prop1>CCC</prop1>
</properties>
<profile>
<id>profile1</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<build>
<plugins>
<plugin>
<groupId>com.xx.yyy</groupId>
<artifactId>xx-plugin</artifactId>
<executions>
<execution>
<id>xx-install</id>
<phase>install</phase>
<goals>
<goal>xx-install</goal>
</goals>
<configuration>
<config1>AAA</config1>
<config2>BBB</config2>
<config3>${prop1}</config3> <!-- I want to override this with value DDD -->
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
Remember that profiles with activeByDefault set to true will get deactivated if any other profile gets activated in your build invocation. See http://maven.apache.org/guides/introduction/introduction-to-profiles.html

If you do not want to change the pom.xml for a plugin you can set the configuration as JVM parameter when running maven as stated in the Generic Configuration chapter of the Maven Guide to Configuring Plugins.
Example:
mvn my-plugin:my-goal -Dplugin.property=ABC
Example for the wildfly plugin (this is where I needed it and did not want to change the pom.xml of a demo project when deploying to a server group in a domain context):
mvn clean install wildfly:deploy -Dwildfly.serverGroups=<server-group-name>
The maven documentation also states that most plugins define help goals to explain users how to configure them.
Exaple for the wildfly plugin:
mvn wildfly:help -Dgoal=deploy -Ddetail

Related

Duplication in maven: are profiles additive to project, or do they replace declared items?

Provided you have the following defined in your POM.xml:
<project>
<!-- ... -->
<build>
<plugins>
<plugin>
<artifactId>plugin-X</artifactId>
<!-- plugin config -->
</plugin>
<plugins>
</build>
<profiles>
<profile>
<id>foo</id>
<build>
<plugins>
<plugin>
<artifactId>plugin-X</artifactId>
<!-- plugin config -->
</plugin>
<plugins>
</build>
<profile>
</profiles>
</project>
If the plugin config for plugin-X is exactly the same for profile foo as it is for a build without a selected profile, do you have to redeclare the plugin at all on the profile level? If so, do you also have to redeclare all config settings for it?
If you declared plugin-Y in project.profile.build.plugins instead of plugin-X (but left it declared on the project level), which plugins would be run when you run mvn -P foo? Only plugin-Y, or also plugin-X?
More generally speaking, are profiles additive to what is declared on the project level, or do they override it? (If they are additive, how do you "remove" entities that were declared on a project level when you run a build profile and don't want them for that specific profile?)
I know profile configuration gets inherited from parent pom files ("from either the build/plugins or pluginManagement sections of the parent") with options "merge", "append", and "override". I think what I really want to know is: how does maven behave when the same/similar information is defined on the project and profile levels in the same pom file...
This isn't a full answer, but another piece of the puzzle - in addition to my earlier comments, and maven's Guide to Configuring Plug-ins.
Given the following pom.xml file:
</profiles>
<properties>
<foo>main</foo>
<bar>main</bar>
</properties>
<build>
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<phase>validate</phase>
<configuration>
<target>
<echo>${foo}</echo>
<echo>${bar}</echo>
<echo>${baz}</echo>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>p</id>
<properties>
<bar>prof</bar>
<baz>prof</baz>
</properties>
</profile>
</profiles>
</project>
When I run mvn validate, I get the following output:
[echo] main
[echo] main
[echo] ${baz}
Running mvn validate -P p however yields:
[echo] main
[echo] prof
[echo] prof
That means that properties at least are merged, appending new items and replacing those that are redefined.
Also, if I add another plugin to the profile (such as surefire), it will execute when running the profile with mvn <phase> -P p, so the profile inherits antrun and adds surefire. Plugin re-definitions however replace the original; adding
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<phase>validate</phase>
<configuration>
<target>
<echo>Tada!</echo>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
only prints Tada!, but no longer the original antrun output (even when changing the new addition's phase to initialize. Adding <inherited>true</inherited> to any of the two plugin definitions doesn't make a difference. The behaviour might be plugin-specific, though.

How to configure maven jar plugin to exclude properties on profile

I have this configuration in my pom
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.2</version>
<configuration>
<excludes>
<exclude>**/logging/*</exclude>
<exclude>**/config/*</exclude>
</excludes>
</configuration>
</plugin>
I use profiles to handle different behaviour from local environment to production environment.
Is it possible not activate the exclusions when executing mvn install with local profile?
I tried to set a blank properties on local environment like this
but the plugin complains.
This is a workaround solution, maybe a better one exists. I think the easiest you could do is to let your DEV environment free from any config of the jar plugin. And then place your PROD config in a dedicated profile :
<profiles>
<profile>
<id>PROD</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.2</version>
<configuration>
<excludes>
<exclude>**/logging/*</exclude>
<exclude>**/config/*</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
When you need to build the production jar, launch :
mvn clean install -PPROD
Are the logging and config files resources for testing only? If yes, put them in ${basedir}/src/test/resources. They'll be on the classpath for your tests but will not end up in the final jar, and you won't need specific jar plugin config.
The best workaround I found is to use an invalid value to filter on when executing on DEV environment.
<profiles>
<profile>
<id>env-local</id>
<activation>
<property>
<name>env</name>
<value>local</value>
</property>
</activation>
<properties>
<jndi.iban0>cont0Data</jndi.iban0>
<config.file.path>classpath:config</config.file.path>
<logging.file.path>classpath:logging</logging.file.path>
<exclude.logging>none</exclude.logging>
<exclude.config>none</exclude.config>
</properties>
</profile>
</profiles>

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}

Define maven profiles outside POM

Is there a way to define my maven profiles outside POM file but not in .m2/settings.xml?
I want to define them in a separate xml file inside the application (way to work efficiently with maven 2 and 3) because I am using maven 2 and intend to switch to 3 soon.
Until Maven 2.2.1 you could define your profiles into the profiles.xml file as a separate file but with Maven 3 this opportunity has been removed. The question ist why do you need a separate file for the profiles?
You may want to go through this maven documentation on build profiles, which describes the types of profiles and how each can be used.
As I see it, profiles cannot be defined outside pom.xml or settings.xml, if you want to use maven 3.
<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>
<profile>
<id>test</id>
<properties>
<build.profile.id>test</build.profile.id>
</properties>
</profile>
</profiles>
And add a filter
<filters>
<filter>src/test/resources/${build.profile.id}/config.properties</filter>
</filters>
And add any directory (dev, prod, test)
I was recently migrating an application to maven3 from maven2. With maven 3 there is no possibility to have external profiles. But what can be done is to have external property files. This can be achieved by maven-properties-plugin
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>properties-maven-plugin</artifactId>
<version>1.0-alpha-2</version>
<executions>
<!-- Associate the read-project-properties goal with the initialize phase,
to read the properties file. -->
<execution>
<phase>initialize</phase>
<goals>
<goal>read-project-properties</goal>
</goals>
<configuration>
<files>
<file>../com.tak/build.properties</file>
</files>
</configuration>
</execution>
</executions>
</plugin>
So here I have explained how to do that http://programtalk.com/java/migrate-from-maven2x-to-maven3x/

How to identify and set a missing environment property in Maven?

I have my build set-up so that I pass in my variable via the command line:
mvn clean install -DsomeVariable=data
In my pom I have:
<someTag>${someVariable}</someTag>
This works fine, but I would like to identify if someVariable is not specified on the command line, and then default it so that my script can continue.
Can this be done in Maven?
You can specify default property value in the properties section of your POM file:
<properties>
<someVariable>myVariable</someVariable>
</properties>
If you want to make sure that the property value is ALWAYS supplied on a command line, then you can use maven-enforcer-plugin.
Here is a link that shows how to enforce system property presence -> http://maven.apache.org/enforcer/enforcer-rules/requireProperty.html
I'll just copy the XML verbatim here in case the above link goes bad.
<project>
[...]
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>1.0.1</version>
<executions>
<execution>
<id>enforce-property</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<requireProperty>
<property>basedir</property>
<message>You must have a basedir!</message>
<regex>\d</regex>
<regexMessage>You must have a digit in your baseDir!</regexMessage>
</requireProperty>
<requireProperty>
<property>project.version</property>
<message>"Project version must be specified."</message>
<regex>(\d|-SNAPSHOT)$</regex>
<regexMessage>"Project version must end in a number or -SNAPSHOT."</regexMessage>
</requireProperty>
</rules>
<fail>true</fail>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
[...]
</project>
You can specify the default value as
<properties>
<someTag>defaultValue</someTag>
</properties>
When you run maven command, you can override that value like this
mvn clean package -DsomeTag=newSpecificValue
You can use profiles instead, but you'll need a profile for each
variable.
<profile>
<id>default-value-1</id>
<activation>
<activeByDefault>false</activeByDefault>
<property>
<name>!someVariable</name>
</property>
</activation>
<properties>
<someVariable>DEFAULT-VALUE</someVariable>
</properties>
</profile>

Resources