Maven2 - problem with pluginManagement and parent-child relationship - maven-2

from maven documentation
pluginManagement: is an element that is seen along side plugins. Plugin Management contains plugin elements in much the same way, except that rather than configuring plugin information for this particular project build, it is intended to configure project builds that inherit from this one. However, this only configures plugins that are actually referenced within the plugins element in the children. The children have every right to override pluginManagement definitions.
Now : if I have this in my parent POM
<build>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.0</version>
<executions>
Some stuff for the children
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>
and I run mvn help:effective-pom on the parent project I get what I want, namely the plugins part directly under build (the one doing the work) remains empty.
Now if I do the following :
<build>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.0</version>
<executions>
Some stuff for the children
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.0.2</version>
<inherited>true</inherited>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
mvn help:effective-pom I get again just what I want, the plugins contains just what is declared and the pluginManagement section is ignored.
BUT changing with the following
<build>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.0</version>
<executions>
Some stuff for the children
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.0</version>
<inherited>false</inherited> <!-- this perticular config is NOT for kids... for parent only -->
<executions>
some stuff for adults only
</execution>
</executions>
</plugin>
</plugins>
</build>
and running mvn help:effective-pom
the stuff from pluginManagement section is added on top of what is declared already. as such :
<build>
<pluginManagement>
...
</pluginManagement>
<plugins>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.0</version>
<inherited>false</inherited> <!-- this perticular config is NOT for kids... for parent only -->
<executions>
Some stuff for the children
</execution>
<executions>
some stuff for adults only
</execution>
</executions>
</plugin>
</plugins>
</build>
Is there a way to exclude the part for children from the parent pom's section ? In effect what I want is for the pluginManagement to behave exactly as the documentation states, that is I want it to apply for children only but not for the project in which it is declared.
As a corrolary, is there a way I can override the parts from the pluginManagement by declaring the plugin in the normal build section of a project ? whatever I try I get that the section is added to executions but I cannot override one that exists already.
EDIT:
I never did find an acceptable solution for this and as such the issue remains open. Closest solution was offered below and is currently the accepted solution for this question until something better comes up. Right now there are three ways to achieve the desired result (modulate plugin behaviour depending on where in the inheritance hierarchy the current POM is):
1 - using profiles, it will work but you must beware that profiles are not inherited, which is somewhat counter intuitive. They are (if activated) applied to the POM where declared and then this generated POM is propagated down. As such the only way to activate the profile for child POM is specifically on the command line (least I did not find another way). Property, file and other means of activation fail to activate the POM because the trigger is not in the POM where the profile is declared.
2 - (this is what I ended up doing) Declare the plugin as not inherited in the parent and re-declare (copy-paste) the tidbit in every child where it is wanted. Not ideal but it is simple and it works.
3 - Split the aggregation nature and parent nature of the parent POM. Then since the part that only applies to the parent is in a different project it is now possible to use pluginManagement as firstly intended. However this means that a new artificial project must be created that does not contribute to the end product but only serves the could system. This is clear case of conceptual bleed. Also this only applies to my specific and is hard to generalize, so I abandoned efforts to try and make this work in favor of the not-pretty but more contained cut and paste patch described in 2.
If anyone coming across this question has a better solution either because of my lack of knowledge of Maven or because the tool evolved to allow this please post the solution here for future reference.
Thank you all for your help :-)

Adding the plugin configuration to pluginManagement means that this configuration will be used if the plugin is declared, but you still need to declare the plugin in the build section of any POM that wants to use it.
The key part that explains this from the section you quoted is:
However, this only configures plugins that are actually referenced within the plugins element in the children
So if you do this in the child pom the configuration from the parent will be applied:
<build>
<plugins>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
</plugin>
</plugins>
</build>
Update: To answer the actual question, the content from the pluginManagement section is always merged with any plugin declaration. To avoid the parent doing this, you can define the pluginManagement section within a profile, and activate that profile on child projects but not the parent. The child projects would then have to declare that profile.
For example:
<profiles>
<profile>
<id>for-children</id>
<build>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.0</version>
<executions>
<!--Some stuff for the children-->
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>
</profile>
</profiles>
<build>
<plugins>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.0</version>
<inherited>false</inherited> <!-- this perticular config is NOT for kids... for parent only -->
<!--some stuff for adults only-->
</executions>
</plugin>
</plugins>
</build>

I always used to think that a child POM can inherit a plugin definition from its parent's pluginManagement section and specify only the executions it wants to run from that plugin by referencing them by ID and binding the execution to a phase. As long as the parent definition is in pluginManagement (and not directly in plugins) and is not bound to a phase, only the specific execution (with ID) will be run in that phase.
From reading the above, and from my own current problem, it looks like that's not true: it looks like a child POM will inherit the entire configuration of the plugin, including all executions. In terms of executions, the only thing the child can do is to override specific values - it cannot pick which executions to run, and which not to.
Is this a bug? What's the use of being able to bind each execution to a phase (or not), if all executions will be run? I've only seen it with maven-dependency-plugin:unpack (bound to package phase), but with other plugins I might just have been lucky...
Damn.

In parent pom you should configure executions with <goals> declared but don't declare <phase>. Then in the child POM you should declare:
<plugin>
<artifactId>some-plugin</artifactId>
<executions>
<execution>
<id>execution-id</id>
<phase>partcular-phase</phase>
</execution>
</executions>
</plugin>
The plugin won't be executed until you define a phase in the child pom. Therefore you'll need to explicitly bind executions to phases in every child POM (or in the middle of hierarchy), but
you won't need to copy-paste configuration of these executions.
Note, that many of plugins have Default Phase, e.g. Enforcer Plugin is bound to validate by default. Even if you don't bind plugin to a phase explicitly, it will be bound anyway and thus the plugin will be executed. To overcome this, use non-existing phase in your parent:
<execution>
<id>execution-id</id>
<goals><goal>some-goal</goal></goals>
<phase>none</phase>
</execution>

You must assign an ID to the execution so maven knows which ones overwrite each other and which are independent.

Related

maven2: how to share a plugin configuration between parent and children pom?

I'm trying to reduce copy/pasting in our maven pom files.
We have one master pom and many children projects pom inheriting from the master.
I want to share a complex plugin definition looking like:
<plugins>
...
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>appassembler-maven-plugin</artifactId>
<configuration>
<!-- many xml lines here -->
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>assemble</goal>
<goal>generate-daemons</goal>
<goal>create-repository</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.codehaus.mojo.appassembler</groupId>
<artifactId>appassembler-booter</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</plugin>
...
</plugins>
When this plugin definition is in the project pom, packaging is well done.
When definition is moved to parent pom (in or in ), then the packaging is not even started.
Is it possible to share a plugin configuration ? How ?
-- Edit after first answers---
I have tried the following:
- put my XL packaging plugin config in the element of my parent pom
- add this lines in my project pom in the element:
<plugins>
...
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>appassembler-maven-plugin</artifactId>
</plugin>
...
</plugins>
but it is not working...
What can be wrong with that ?
-- last edit --
I think I get what was the problem:
the plugin re-use declaration should be declared in a profile build.
I done that in an always enabled plugin and now it is working fine.
Thanks a lot.
You could wrap the plugins of the parent in a <pluginManagement> tag.
<build>
<pluginManagement>
<plugins>
<plugin> ... </plugin>
</plugins>
</pluginManagement>
</build>
Children plugins will then inherit the configurations when they declare the plugin in their build tag.
Have you tried using the plugin management feature of Maven? It'll allow you to push that configuration information down to the children pom.xml files from the parent pom.xml:
<build>
<pluginManagement>
<plugins>
<plugin>your_plugin</plugin>
</plugins>
</pluginManagement>
</build>
Now, not all plugins are as well done as those from the org.apache.maven.plugins group. It may be necessary to move your configuration section in between your execution elements.

Copy dependencies maven war

When I try to use the plugin "maven-war-plugin", it copies all libraries to / WEB-INF/lib, how to copy to another directory? Example: "/ libtest"
I'm not sure to understand why you need to do this but I see two points here:
Avoiding dependencies to get copied into WEB-INF/lib (if not, then just skip the part related to 1.)
Getting them copied to another directory.
For 1. I'm assuming you need the dependencies (because you want to compile against them) but if you don't want the Maven War Plugin to copy them in WEB-INF/lib, you'll have to play with their scope, for example by declaring them as provided.
For 2. the Maven Dependency Plugin will be helpful here and I think you could use dependency:copy-dependencies, for example during the pre-package phase. Use it like this:
<project>
[...]
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>pre-package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<!-- configure the plugin here -->
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
[...]
</project>
And configure the outputDirectory (and other parameters you could need).
Use the maven-dependency-plugin.

Configure Maven plugins to stick together

I have parent pom which configures certain plugins
<pluginManagement>
</plugins>
<plugin>
<artifactId>gmaven-plugin</artifactId>
...
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
...
</plugin>
<plugin>
<artifactId>cargo-maven2-plugin</artifactId>
...
</plugin>
</plugins>
</pluginManagement>
And I have tree of poms which are represent integration tests
A-\
a1
a2
B-\
b1
b2
C-\
D-\
d1
d2
In each a,b,d products I do
<build>
<plugins>
<plugin>
<artifactId>gmaven-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
</plugin>
<plugin>
<artifactId>cargo-maven2-plugin</artifactId>
</plugin>
</plugins>
</build>
The problem is when I will need to add fourth plugin to integration test process for example my custom plugin I will need to move
through all of the integration modules and do manual adding.
You can advice me to remove <pluginManagement> to allow all child just to use them implicitly.
Yes, but in products which are just 'pom' I don't want plugins to do anything: create some resources and put jboss configuration directories.
I wonder is there some kind of
<pluginsBundle>
<groupId>my.group</groupId>
<artifactId>my-integration-test-bundle</artifactId>
<plugins>
<plugin>
<artifactId>gmaven-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
</plugin>
<plugin>
<artifactId>cargo-maven2-plugin</artifactId>
</plugin>
</plugins>
</pluginsBundle>
To allow me use it just like
<plugin>
<groupId>my.group</groupId>
<artifactId>my-integration-test-bundle</artifactId>
<runOnce>true</runOnce>
</plugin>
I would like to add option like
<runOnce>true</runOnce>
to be able to start application server and deploy target only one time per maven launch.
I don't know of a mechanism that does exactly what you need. Your best bet is to define a parent pom with those plugins defined in the build section, rather than the pluginManagement section. In this case the plugin configuration will always be defined. Adding the configuration to a profile in the parent means you can exercise some control over the activation of those plugins.
One refinement to consider is that you can control activation of a profile by the presence or absence of a file. This way you can define the profile in the parent, but have it deactivated in that project because of the marker file being present in the parent. Child projects would not have the marker file in their source, so the profile would be activated for those projects. You can reverse the behaviour by using missing instead of exists if that makes sense for the majority of projects.
<profile>
<id>build</id>
<activation>
<file>
<missing>src/main/resources/build.marker</missing>
<!-- or if you want to enable the profile when the file does exist:
<exists>src/main/resources/build.marker</exists-->
</file>
</activation>
<build>
</plugins>
<plugin>
<artifactId>gmaven-plugin</artifactId>
...
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
...
</plugin>
<plugin>
<artifactId>cargo-maven2-plugin</artifactId>
...
</plugin>
</plugins>
</build>
</profile>
Alternatively, you could try writing custom plugin with a lifecycle that executes all the required mojos in a forked lifecycle. I recently answered another question with details of how to do this.
Another alternative is to write another plugin that uses Maven shared-io to apply a descriptor
to the pom, that descriptor can define arbitrary configuration that is merged into the pom. Another answer describes how this can be done.
AFAIK, there is no way to declare a bundle of plugins that could be used somewhere else... but there is inheritance.
What about creating a pom with the <plugins> declaration in the <build> section and inheriting from this pom in your integration tests projects? This looks like feasible.

Maven-2: avoid default packaging?

My project uses many assemblies, hence I'm interested only in the assemblies.
On executing mvn install apart from the assemblies, I'm getting the default packaged .jar.
How can I avoid this?
I have a pom.xml similar to the one you have provided.
On executing mvn install, I'm getting App1.jar, App2.jar, and snapshot jar containing all contents
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2-beta-2</version>
<executions>
<execution>
<id>assemblyone</id>
<phase>compile</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<finalName>App1</finalName>
<appendAssemblyId>false</appendAssemblyId>
<descriptors>
<descriptor>${basedir}/src/main/resources/assemblies/report.xml</descriptor>
</descriptors>
</configuration>
</execution>
<execution>
<id>assemblytwo</id>
<phase>compile</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<finalName>App2</finalName>
<appendAssemblyId>false</appendAssemblyId>
<descriptors>
<descriptor>${basedir}/src/main/resources/assemblies/src.xml</descriptor>
</descriptors>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
How can I avoid this snapshot (not sure of the exact term) jar and ensure that only assemblies are created?
I can read your question two ways, I've outlined answers for both below. If neither is correct, can you modify your question with a bit more explanation please.
1) Do you mean you have a project with default (jar) packaging, and you want to avoid the creation of the jar when no assembly is defined? If this is the case, what is the build achieving if no assembly is defined?
2) Do you instead mean that you are running mvn assembly:assembly to generate the assembly and want to know how to get that assembly when running the install goal?
For option 2, you can bind the assembly-plugin to a lifecycle phase to ensure it is always run, if you specify that <appendAssemblyId> should be false, then the assembly will replace the default jar.
For example, this configuration will invoke the assembly plugin during the packaging phase and replace the default jar:
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2-beta-2</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<appendAssemblyId>false</appendAssemblyId>
<descriptors>
<descriptor>src/main/assembly/archive.xml</descriptor>
</descriptors>
</configuration>
</execution>
</executions>
</plugin>
For option 1, this is actually quite tricky to do. The best I can think of is to specify that the project has pom packaging and configure the project with the executions normally bound to the jar lifecycle in a profile. The lifecycle bindings you'd need to configure are listed in the introduction to the build lifecycle
I'm not sure that you can really do that in a really simple way.
A solution is to call the clean plugin once the build is achieved, by doing that:
<build>
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<executions>
<execution>
<id>auto-clean</id>
<phase>package</phase>
<goals>
<goal>clean</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
...
</build>
This way, the JAR created in the target/ directory will be deleted at the end of the Maven2 execution.
However, you will have to define another directory to store the assemblies created by Maven2. Otherwise, it will be deleted by the call of the clean plugin... If you want to store them in the directory assemblies-target/, you can add that in the pom.xml file:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2-beta-4</version>
<configuration>
...
<!-- Copy the ZIP in target/ of the ROOT directory. -->
<outputDirectory>assemblies-target</outputDirectory>
</configuration>
...
I think it would be much more clear if you showed us your whole POM and the artifacts that are being built. I can only guess as to what the problem is because your terminology is not what I am familiar with. This is my guess as to the problem: you have a POM configured to generated two assembly JARs, but you get a third JAR for the POM itself. In other words, if your POM's artifactId is MyApp, you are getting a MyApp-1.0.0.jar or similar in addition to the two JARs you actually want.
If that is the case, the problem boils down to that you are using Maven to create multiple artifacts from a single module. Maven is designed to produce only one primary artifact from each module. What I would do is change your POM to have a packaging type of "pom" and give it two modules in a <modules> section named App1 and App2. Create sub-directories under your module, one for each App. Give them each a POM configured for a single assembly, with a packaging type of "jar". Move the code/files/etc. as appropriate into each sub-module so there aren't any remaining in the parent module.
With Maven, if you find yourself generating two artifacts from one module (which you are), you should first consider that you are probably violating a Maven best-practice and rearrange things so you only produce one artifact per module.
Please let me know if this doesn't make sense and I will try to clarify.

Is it possible to override the configuration of a plugin already defined for a profile in a parent POM?

In a POM parent file of my project, I have such a profile defining some configurations useful for this project (so that I can't get rid of this parent POM) :
<profile>
<id>wls7</id>
...
<build>
<plugins>
<!-- use java 1.4 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<fork>true</fork>
<source>1.4</source>
<target>1.4</target>
<meminitial>128m</meminitial>
<maxmem>1024m</maxmem>
<executable>%${jdk14.executable}</executable>
</configuration>
</plugin>
</plugins>
</build>
...
</profile>
But in my project I just would like to override the configuration of the maven-compiler-plugin in order to use jdk5 instead of jdk4 for compiling test-classes.
That's why I did this section in the POM of my project :
<profiles>
<profile>
<id>wls7</id>
<activation>
<property>
<name>jdk</name>
<value>4</value>
</property>
</activation>
<build>
<directory>target-1.4</directory>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<executions>
<execution>
<id>my-testCompile</id>
<phase>test-compile</phase>
<goals>
<goal>testCompile</goal>
</goals>
<configuration>
<fork>true</fork>
<executable>${jdk15.executable}</executable>
<compilerVersion>1.5</compilerVersion>
<source>1.5</source>
<target>1.5</target>
<verbose>true</verbose>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
...
</profiles>
and it's not working ...
I even tried to override the configuration in regular plugin sections of my POM (I mean, not for a specific profile but for my whole POM).
What could be the problem ?
To clarify some of my requirements :
I don't want to get rid of the parent
POM and the profile (wls7) defined
inside it (since I need many and many
properties, configurations, ...) and
that is not the process in my
company.
A solution based on duplicating
the parent POM and/or the profile
defined inside it is not a good
one. Since if the responsible of
the parent POM change something, I
would have to report it in mine.
It's just an inheritance matter (extend or override a profile, a configuration from an upper-level POM) so I think it should be possible with Maven 2.
Overriding configurations from a parent pom can be done by adding the combine.self="override" attribute to the element in your pom.
Try changing your plugin configuration to:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<executions>
<execution>
<id>my-testCompile</id>
<phase>test-compile</phase>
<goals>
<goal>testCompile</goal>
</goals>
<configuration combine.self="override">
<fork>true</fork>
<executable>${jdk15.executable}</executable>
<compilerVersion>1.5</compilerVersion>
<source>1.5</source>
<target>1.5</target>
<verbose>true</verbose>
</configuration>
</execution>
</executions>
</plugin>
For more information on overriding plugins, see: http://maven.apache.org/pom.html
i had the same issue. By default my maven war plugin excluded a html file. But in my acceptance-tests profile i wanted this file included. So when i added in the maven war plugin again it did not override the default.
To resolve this issue i passed in the combine.self attribute and worked fine.
Default build:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.4</version>
<configuration>
<packagingExcludes>swagger-ui/client.html</packagingExcludes>
</configuration>
</plugin>
Acceptance test profile:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.4</version>
<configuration combine.self="override"/>
</plugin>
Did you try to deactivate the wls7 profile (since maven 2.0.10):
Starting with Maven 2.0.10, one or
more profiles can be deactivated using
the command line by prefixing their
identifier with either the character
'!' or '-' as shown below:
mvn groupId:artifactId:goal -P !profile-1,!profile-2
This can be used to deactivate
profiles marked as activeByDefault or
profiles that would otherwise be
activated through their activation
config.
And then add your configuration in a profile with a different name or directly in your pom.xml.