Maven - Parent Pom - Child Inheritance - maven

I am attempting to make a maven parent pom setup where I don't have to declare any plugin information in my child pom, everything is taken from the parent pom.
I essentially have it working where I've put all my plugins with there configurations in to the parent pom. Then in the child poms I have to declare the plugin still, but without the version and configuration information.
I don't want to have to declare the plugin in the child at all. This way I can add new features (such as pmd, freebugs, etc) to my parent pom and all my projects now have them working. How can I accomplish this?
Parent Pom
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-scm-plugin</artifactId>
<version>1.0</version>
<inherited>true</inherited>
<configuration>
<providerImplementations>
<cvs>cvs_native</cvs>
</providerImplementations>
<systemProperties>
<property>
<name>maven.scm.perforce.clientspec.name</name>
<value>${perforceClientSpec}</value>
</property>
</systemProperties>
</configuration>
</plugin>
Child Pom still needs this but I don't want to have to do this if I can avoid it:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-scm-plugin</artifactId>
</plugin>

<pluginManagement> section 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 (so you have to explicitly specify them, as you indicated). See more here.
If you want to avoid this, you can put this information into <build> section like this:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-scm-plugin</artifactId>
<version>1.0</version>
<configuration>
<...>
</configuration>
<executions>
<...>
</executions>
</plugin>
</plugins>
</build>

Instead of using pluginManagement, try using just <plugins> tag. It should be auto inherited. You may optionally override configuration in child pom. Check that by mvn help:effective-pom

You can't avoid naming the plugin in the child pom, cause how should maven know which plugin are you using. The pluginManagement section is intended for defining the versions of plugin furthermore it's used to define a default configuration.

Related

Should pluginManagement be used in submodules?

I am reading sonatype's tutorial on multimodule projects and I see that in submodule they use the <pluginManagement> configuration like this:
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<testFailureIgnore>true</testFailureIgnore>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
This confuses me as I thought that <pluginManagement> is to be used in parent POM to provide common plugin configuration for submodules. What are the reasons for using plugin managment in children poms ?
Most of the time <pluginManagement> is used in parent pom files.
It configures plugins. But makes them not active part of the build. Therefor you need to add them to the <plugins> part of the Maven pom file. Most not done in parent pom files, but done in the (sub) modules, using / refering to that (parent) pom.
I think this is special to the use of the surefire plugin.
Since you execute the plugin with mvn test the surefire plugin will be executed with the configuration specified in the pluginManagement block. Other plugins are not executed directly but by binding them to another lifecycle phase and thus must be specified in the plugin block.
See the usage page of the surefire plugin.

Installing and compiling Maven artifacts on Java 8

I have a project with a pom.xml that has the following <build> declaration:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
When I run mvn install on this project, it compiles the project, runs unit tests and publishes it to my local repo. I am trying to learn a little more about Maven here, and am having a tough time finding documentation/explanations on the following:
How am I able to run mvn install, if the POM doesn't declare it under build/plugins? Does maven-compiler-plugin include maven-install-plugin, if so, how could I have figured that out?
Most importantly: the value of build/plugins/plugin/configuration/source and .../target are both set to 1.8. If my machine has Java 8 on it, and I run mvn install on this project without any errors, does that guarantee that the project builds with Java 8? I'm looking at the docs for the Compiler Plugin and don't see those source/target configs listed anywhere.
First you should learn what the build life cycle is and how it works and how the plugins are bound to the life cycle by default.
Furthermore you should understand that in Maven every project inherits from the super pom file which is part of the maven distribution (the package you have downloaded). The super pom defines the default folder layout and some versions of plugins.
The question to define the maven-compiler-plugin as you did is to be very accurate simply wrong. You should have defined it like the following:
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
This would overwrite the definition which is inherited by the super pom and changes it's configuration. In your case i would suggest to change the definition into this:
<project>
...
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
..
</project>
The encoding should be set globally cause there are other plugins which use this definition like the maven-resources-plugin. The usage of the above property simplifies this, cause every plugin which has an option for encoding will use the default as defined in the property.
To be sure using the correct version of Java (your JDK on your machine) you have to use the maven-enforcer-plugin.
Apart from that please take a look onto the plugins page which shows the most up-to-date releases of the plugins.
As a good documentation i can recomment the Books on Maven but be aware they are written with Maven 2 in mind. So if something is not clear ask on users mailing list of here on SO.

Maven Compiler Plugin

I know Maven compiler plugin by DEFAULT is bind to :
compile
test compile
life cycles, in general without specifying addition configuration, we don't have to
explicitly define it in our POM, but I still seen experienced developer putting things like
this in their POM, e.g
<build>
<plugins>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
</plugins>
</build>
I wander what's the point? and why is he doing this?
For the shade plugin, he is probably using POM inheritance. Look in the parent POM hierarchy for a pluginManagement section, there is probably shade plugin configuration there that he is pulling into this module.
For the compiler plugin, I do not know. You are correct, for jar/war/ear/ejb projects Maven will pull in the compiler config automatically, even if he has defined specific configuration in a parent POM's pluginManagement section.
If they put such things in their pom's they don't understand Maven. You should define the version of the plugins your are using in your build. This is done by:
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin<artifactId>
<version>3.1</version>
<configuration>
<target>1.6</target>
<source>1.6</source>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin<artifactId>
<version>2.3</version>
</plugin>
</plugins>
</pluginManagement>
</build>
This should be usually located into a pom file known under Company POM which defines versions of plugins for projects within a company.
Furthermore based on the life-cycle definition in Maven the Maven Super POM which contains the default bindings there you could see that particular plugins versions are defined.This means if you upgrade your Maven version you start using different plugin versions which is fact not the best related to build reproducibility. So the best practice is to define all used plugins like here as an example.. Based on the definition you shouldn't need to mention anything in your build-tag area if you have a defined packaging type (This is one of those Convention Over Configuration paradigm hints).

How do I disable the maven-compiler-plugin?

I have a maven project that uses the aspectj-compiler-plugin. I use intertype declarations so there are references to Aspect code in my Java code. Because of this, the maven-compiler-plugin fails to compile since it does not compile the aspect code.
My question is: how do I disable the maven-compiler-plugin from running because it is not doing anything useful?
There are several ways that I can get this project compiling, but they are sub-optimal:
Add exclusion filters to the maven-compiler-plugin. The plugin will still run, but it will not try to compile anything. Problem is that this breaks the ajdt project configurator in Eclipse
Move all java code to the aspectj folders. This doesn't feel right either.
You can disable the a plugin by set the phase of the plugin to none.
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<executions>
<execution>
<id>default-compile</id>
<phase>none</phase>
</execution>
</executions>
</plugin>
</plugins>
</build>
In Maven 3, the following will do this, for example disabling the clean plugin:
<build>
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>2.4.1</version>
<executions>
<execution>
<id>default-clean</id>
<phase>none</phase>
</execution>
</executions>
</plugin>
</plugins>
</build>
The same technique can be used for any other plugin defined in the super-POM, the packaging type, or the parent POM. The key point is that you must copy the <id> shown by help:effective-pom, and change the <phase> to an invalid value (e.g. "none"). If you don't have the <id> (as e.g. in Jintian DENG's original answer – it has since been edited to add one), it will not work, as you have discovered.
Either configure the skipMain parameter:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<skipMain>true</skipMain>
</configuration>
</plugin>
</plugins>
</build>
Or pass the maven.main.skip property:
mvn install -Dmaven.main.skip=true
The reason maven-compiler-plugin executes in the first place is because you trigger one of the default lifecycle bindings. For example if you're packaging jar using mvn package, it will trigger compile:compile at compile phase.
Maybe try not to use the default lifecycle, but use mvn aspectj:compile instead.
http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html has more information about maven default lifecycle bindings

How to share POM fragments between different POMs

I am currently struggling with Maven: I have a complex project made of several nested modules and for some of those modules, I have similar configurations in the POMs.
I would like to make it clean. Actually, I would like to define a "runnable-jar" common configuration and activate it in some modules.
Here is the POM fragment I would like to share between several projects:
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<!-- Use a custom descriptor, with suffix "bin" -->
<descriptors>
<descriptor>src/main/assembly/runnable-jar-assembly.xml</descriptor>
</descriptors>
<!-- Add main class to manifest -->
<archive>
<manifest>
<mainClass>${mainClass}</mainClass>
</manifest>
</archive>
</configuration>
<!-- Add build of this package to lifecycle -->
<executions>
<execution>
<id>make-runnable-jar</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
In some of the POMS, I would like to be able to do something like:
<!-- Set the main class -->
<properties>
<mainClass>my.main.Class</mainClass>
</properties>
<!-- Activate runnable jar build -->
<import>src/main/pom/runnable-jar-pom.xml</import>
I have searched for a mean to import some XML fragments into a POM, or to define a whole XML nodeset macro.
For what I have found, the closest solution would be to define a profile in the parent POM and activate it in some sub modules by testing the presence of a file. See this related question. But I am facing the problem of the {basedir} property not being set correctly inherited / set.
I find it very surprising to need a hack to do something so basic (=usual). How do you usually handle this in Maven ?
I have just discovered something that might solve my problem :
A module does not require to be a sub-module of its parent module.
Parent and sub-module relationships are separate concepts.
You can specify a parent POM module that is not the actual parent folder in your folder structure, by using the relativePath attribute (as explained in the doc)
In my case, I use the following layout:
main-project
utils (parent:main-project)
cli-programs (parent:main-project)
generic-cli (parent:cli-programs; Dummy & empty POM module)
cli-1 (parent:generic-cli)
cli-2 (parent:generic-cli)
Then, in generic-cli/pom.xml I can declare a configuration that is common to all my cli programs (like custom test suites, runnable-jar packaging, etc).
One way to do this would be to declare your <plugin> code inside <pluginManagement> of the parent pom of your multi-module project. The individual modules can then have a <plugin> section which can use this without redeclaring the contents.
Parent pom:
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
... all the details...
</plugin>
...
</plugins>
</pluginManagement>
Child poms:
<plugins>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
</plugin>
</plugin>
Maven-tiles solves this. It's also on the roadmap for maven 3.x, tracked here.
not a total answer but a solution to the basedir problem is to use a common layout of the modules, e.g. root/modules/moduleA root/modules/moduleB.
You can't build the modules formm their own directory anymore, only through thr parent project. But you can work with the profiles.

Resources