Defer properties evaluation in Maven sub-modules - maven

I have some problems trying to run maven in a 3-level multi-module project.
The first level is the super-pom, which defines antrun tasks. It is located in an external repository.
The second one refers to the super-pom, and only include the definition of submodules. Let's say it is in /project
The third level contains the sub-module and its items are located at /project/moduleN.
At the first level, AntRun tasks includes calls to "${project.basedir}".
When I use maven, I go to the second level pom folder and run mvn clean install.
As it only includes sub-modules, it tries to compile them but ${project.basedir} has already been evaluated as being /project, and not /project/moduleN.
I would like to defer the evaluation of those expressions in order to replace them with values from my sub-modules, and not from the pom including them, but I can't find a way to do so.
Here are excerpts from POM files to understand what's going on :
Super POM
<groupId>org.example</groupId>
<artifactId>superpom</artifactId>
<packaging>pom</packaging>
...
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
...
<exec dir="${project.basedir}" ...></exec>
</plugin>
</plugins>
Project POM
<parent>
<groupId>org.example</groupId>
<artifactId>superpom</artifactId>
</parent>
<groupId>org.example</groupId>
<artifactId>projectPom</artifactId>
<packaging>pom</packaging>
<modules>
<module>module1</module>
<module>module2</module>
</modules>
Modules POM
<parent>
<groupId>org.example</groupId>
<artifactId>projectPom</artifactId>
</parent>
<groupId>org.example</groupId>
<artifactId>moduleNPom</artifactId>
<packaging>jar</packaging>

Related

Exclude parent and its children or modules in maven command executing lifecycle

Executing mvn clean install -pl !Parent2 does NOT apply life-cycles on Parent2 children's nor modules. While all sub-projects are in same level I try to combine Project2 & Project2 into one parent Parent2 to exclude it only from many life-cycles. How could this be done ?
Similarly mvn clean install -pl Parent2 only applied on Parent2 without its children/modules !!
Here are the latest POMs I reached to structure. Noting that my only restriction is keeping folders of all in same level (under Parent1)
Parent1
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>any</groupId>
<artifactId>Parent1</artifactId>
<version>whatever</version>
<packaging>pom</packaging>
<modules>
<module>Parent2</module>
<module>Project1</module>
</modules>
</project>
Parent2
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>any</groupId>
<artifactId>Parent1</artifactId>
<version>whatever</version>
</parent>
<packaging>pom</packaging>
<artifactId>Parent2</artifactId>
<modules>
<module>../Project2</module>
<module>../Project3</module>
</modules>
</project>
Project1
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>any</groupId>
<artifactId>Parent1</artifactId>
<version>whatever</version>
</parent>
<packaging>jar</packaging>
<artifactId>Project1</artifactId>
</project>
Project2 (Project3 is exactly the same)
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>any</groupId>
<artifactId>Parent2</artifactId>
<version>whatever</version>
<relativePath>../Parent2</relativePath>
</parent>
<packaging>jar</packaging>
<artifactId>Project2</artifactId>
</project>
I'm interested in applying the exclusion on sub-modules as well. However mvn clean install -pl Parent2 -amd works as wanted & expected applying clean & install into Parent2, Project2 & Project3. However, as pointed by Pawl's comment and according to MNG-5230 issue
Nested modules are not excluded by parent module. The exclusion method mimics the inclusion method and its matcher does not support wildcards etc. So to cascade exclusion would necessitate an extra flag like -amd.
The dependency graph is filtered in the following order when using
-pl:
1. included projects + possibly upstream and downstream
2. excluded projects
3. skipping for resume projects
So it should be possible to directly exclude nested modules as they should be present in the intial dependency graph before filtering starts.
So excluding nested modules using their parent/holder pom is not possible. Here is how I worked around it to solve this. Simply using profiles and completely removing sub-modules outside profiles definition solved it.
In short is using profiles to identify modules with noting that modules identified outside profiles are shared no matter what profile is activated
Example as of OP projects naming followed
Parent1 (Added Project4 as same as Project1 just for clarifying)
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>Parent1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<profiles>
<profile>
<id>multi-modules-profile</id>
<modules>
<module>Parent2</module>
<module>Project2</module>
<module>Project3</module>
</modules>
</profile>
<profile>
<id>simple-module-profile</id>
<modules>
<module>Project1</module>
</modules>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
</profiles>
<modules>
<module>Project4</module>
</modules>
Project1 (& Project4 is similar)
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.example</groupId>
<artifactId>Parent1</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>Project1</artifactId>
Parent2
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.example</groupId>
<artifactId>Parent1</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>Parent2</artifactId>
<packaging>pom</packaging>
Project2 (& Project3 is similar)
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.example</groupId>
<artifactId>Parent2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../Parent2</relativePath>
</parent>
<artifactId>Project2</artifactId>
Now running mvn clean would apply on Parent1, Project1 & Project4 because Project1 is in profile that is activated by default (without specifying profile during the execution). This has same effect running mvn clean -P simple-module-profile because Project4 is shared outside profiles definitions.
Finally, running mvn clean -P multi-modules-profile will be applied to Parent1, Project4, Parent2, Project2 & Project3 leaving Project1 out which is desired. Notice Project4 is always in because it's outside profiles definitions.
EDIT: the answer applies only to:
Similarly mvn clean install -pl Parent2 only applied on Parent2 without its children/modules !!
Use mvn -pl Parent2 -amd clean install to build Parent2 and all of it's modules.
See the reference: https://books.sonatype.com/mvnref-book/reference/_using_advanced_reactor_options.html#_making_project_dependents

project.build.sourceEncoding defined in Parent Pom Ignored in Child

Given a parent pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.acme</groupId>
<artifactId>acme-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
<java-version>1.8</java-version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<com.acme.dynamite-version>0.0.1-SNAPSHOT</com.acme.dynamite-version>
// etc
</properties>
</project>
and child pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.acme</groupId>
<artifactId>child</artifactId>
<version>dev-SNAPSHOT</version>
<packaging>jar</packaging>
<parent>
<groupId>com.acme</groupId>
<artifactId>acme-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>com.acme</groupId>
<artifactId>dynamite</artifactId>
<version>${com.acme.dynamite-version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
The property, com.acme.dynamite-version, which is explicitly referenced in the child pom is resolved, however project.build.sourceEncoding is ignored. The Jenkins build of 'mvn clean install' throws a warning:
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
Is there a way to get the child pom to recognize project.build.sourceEncoding? This is not a multi module project, I am just trying to consolidate properties in one place
Properties defined in a parent POM are inherited in the child POM... but for that, the parent POM defining those properties needs to be installed before the child is built. And this is the issue here:
Your parent, having a version 0.0.1-SNAPSHOT, right-fully declares the property <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>. However, that version of the parent defining this property is not installed in your local repository.
When trying to build the child project, Maven will look-up any dependencies and parent POM in your local repo. It will find the version of the parent without that property and continue the build. Then, the maven-resources-plugin will emit this warning because no encoding have been set. (Setting the project.build.sourceEncoding also sets by default the encoding used by this plugin).
The solution is to build the parent first.
In a multi-module Maven project, you simply need to build the parent: Maven will order the reactor in such a way that dependant projects are built first; so in this case, the parent would be built first, and then the child (or module in this case), thereby ensuring that all properties defined in the parent are accessible to the child.
Outside of a multi-module Maven project, the idea is still the same, but you then need to perform two distinct builds: first the parent to install the right version into your local repository, and then the child. Note that when such parents are not used as aggregator projects, but more as building blocks consolidating common properties for children to inherit from, it would be preferable to have a distinct release cycle with it: consider making a release of your parent, so that every child can inherit that particular version.
You need to add the maven-resources-plugin in order to activate filtering, like here:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.1</version>
<configuration>
...
<encoding>UTF-8</encoding>
...
</configuration>
</plugin>
</plugins>
...
</build>

TeamCity, Maven Build not found child module

I've Maven project with one subproject, when I run my install task on parent project from IDEA (IntelliJ IDEA) all works fine and maven resolve child module.
My projects are versioned on subversion, and this is the filesystem structure:
project
|--pom.xml
|--subproject
|
|-- branches
|-- tags
|-- trunk (here there is my subproject source, also pom.xml file)
I've create project with its subproject, from svn URL, on teamcity server.
When I run Build on parent project it fail and return me the following error:
[Step 1/1] Error reading Maven project: Some problems were encountered while processing the POMs:
[ERROR] Child module /opt/buildAgent/work/ee114e0c77ee2c44/subproject of /opt/buildAgent/work/ee114e0c77ee2c44/pom.xml does not exist #
How can I say to parent-project-build where it find the child module?
Is there something else wrong?
Parent POM:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>it.company.project</groupId>
<artifactId>MyProject</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>MyProject</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<modules>
<module>Foo</module>
</modules>
</project>
Child POM:
<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>it.company.project</groupId>
<artifactId>MyProject</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<groupId>it.company.subproject</groupId>
<artifactId>subproject</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>subproject</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.java</include>
</includes>
</resource>
</resources>
</build>
</project>
EDIT:
I added new parameter (pathSubproject) to my parent pom.xml, so when I run the parent build it skipped the previous error, but now it crash when trying to resolve parent dependency on the subproject. So I added a new parameter also at subproject (parentPath) and I passed it to relativePath inside parent tag.
Non-resolvable parent POM: Could not find artifact it.company.project:MyProject:pom:1.0-SNAPSHOT and 'parent.relativePath'
I think that my subproject POM not resolve the properties that I put inside <relativePath tag.
Is possible pass a properties to relativePath tag?
Thanks
In the <modules/> section of your parent project's pom, each module listed is a relative path to the directory containing the module.
So if you don't want to change the directory structure, you should be able to refer to the trunk of your subproject using <module>subproject/trunk</module>.
This does seem a bit clumsy though. If you are using the aggregator / modules pattern, I would recommend that project and subproject are both in the same SVN respository. If that isn't appropriate, then your subproject might not really be a module, and should be a dependency or have project as its parent artifact.
I solve my problem by creating 2 profile in my parent pom, the first one builds the parent application with all submodules, while the latter build only the the parent application.
In TeamCiTY build configuration settings I specified (inside Additional Maven command line parameters) the profile that build only parent module, and after I built the parent Application.
After that I built the parent application I built all submodules, and then I was able to build parent application with all modules.
I'm not sure that this is the right way, but in my case it worked well.

Maven: POM modules and submodules hierarchy

My project is structured like this:
.
|--module
| `-- pom.xml
| --submodule
| `-- pom.xml
`-- pom.xml
The POM's (simplified):
Project:
<project>
<modelVersion>4.0.0</modelVersion>
<artifactId>project</artifactId>
<name>Project</name>
<groupId>org.myorg</groupId>
<version>1.0.6-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>module</module>
</modules>
(...)
</project>
Module:
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.myorg</groupId>
<artifactId>project</artifactId>
<version>1.0.6-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>module</artifactId>
<name>Module</name>
<groupId>org.myorg</groupId>
<version>1.0.6-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>submodule</module>
</modules>
(...)
</project>
Submodule:
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.myorg</groupId>
<artifactId>module</artifactId>
<version>1.0.6-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>submodule</artifactId>
<name>Submodule</name>
<groupId>org.myorg</groupId>
<version>1.0.6-SNAPSHOT</version>
<packaging>jar</packaging>
(...)
</project>
When run maven install in POM's project or module the project is built sucessfully. But, when run in submodule occours this error:
Failed to execute goal on project submodule: Could not find artifact org.myorg:project:pom:1.0.6-SNAPSHOT
Why my submodule not find the POM project? The relative path is specified.
The first thing which i noticed is that every sub-module which has a parent contains the line:
<relativePath>../pom.xml</relativePath>
which is useless, cause it's default in maven or in other word just remove it.
Furthermore in a multimodule build you shouldn't define the version. In case if the groupId is always the same you can omit the groupId as well, cause the current module inherits the version from it's parent.
module: pom.xml
<project>
<parent>...
</parent>
<artifactId>module</artifactId>
<packaging>pom</packaging>
<name>Module</name>
<modules>
<module>submodule</module>
</modules>
(...)
</project>
Apart from that you can't go into a sub-module and call
mvn install
If you like to install a separate module of a multi-module build you should use a thing like this:
mvn -amd -pl submodule install
which will do what you like to do, but usually you should install a full mulit-module build unless you exactly know what you are doing.
The options -amd is an abbrevation for --also-make-dependents. The -pl is an abbreviation for --projects to define a list of project which should be made during the call.
First you need to run mvn install on root project it will creates the artifact in your local maven repo. From the second time on wards you can run sub module only. If you don't run on root project maven wont create any artifact for your project so when you run on sub module it unable to find the artifact from the maven repo.

Maven site on multi module project could not resolve dependency

I want to split my continous integration job (Hudson) into two steps. (Because the runtime with build and reporting together takes too long.)
In the first job, I build my multi module maven project with "mvn package" successfully.
Then I copy my workspace to another location and try to build the project again only with the goal "site" and/or findbugs/checkstyle/pmd to create reports.
But this doesn't work! Maven can't resolve a dependency of my submodules.
(But all JARs are available in its target folders.)
Example:
My structure looks like this:
Parent
A
B
C
D
Project C has as dependency project B.
When I build everything with "mvn site", it generates for project A and B all reports. But halted at project C with error message "Could not resolve dependencies for project B."
But project B is already builded with "mvn package". I.e. I can find the JAR file of project B in its target folder.
Is there any way to resolve the dependency from submodule B without a "mvn install"?
(I don't wanna do this on my ci server. I fear it could be dangerous for other jobs with the same code base.)
Update 08/20/12:
POM of root folder:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<name>Foo</name>
<groupId>foo</groupId>
<artifactId>bar</artifactId>
<version>1.0</version>
<packaging>pom</packaging>
<modules>
<module>parent</module>
</modules>
</project>
Parent POM:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<name>Foo</name>
<groupId>foo</groupId>
<artifactId>parent</artifactId>
<version>1.0</version>
<packaging>pom</packaging>
<modules>
<module>../bar-a</module>
<module>../bar-b</module>
<module>../bar-c</module>
<module>../bar-d</module>
</modules>
[...]
<reporting>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
<version>2.5.1</version>
[...]
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<version>2.7.1</version>
[...]
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>2.9.1</version>
[...]
</plugin>
</plugins>
</reporting>
</project>
POM of B:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>foo</groupId>
<artifactId>parent</artifactId>
<version>1.0</version>
<relativePath>../parent</relativePath>
</parent>
<name>Bar B</name>
<artifactId>bar-b</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
[...]
</project>
POM of C:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>foo</groupId>
<artifactId>parent</artifactId>
<version>1.0</version>
<relativePath>../parent</relativePath>
</parent>
<name>Bar C</name>
<artifactId>bar-c</artifactId>
<packaging>jar</packaging>
[...]
<dependencies>
<dependency>
<groupId>foo</groupId>
<artifactId>bar-b</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
[...]
</project>
I was facing quite the same "long time" issue.
The only way (I think) to solve it with your way of working is indeed mvn install, as you suggested it.
But the problem is indeed the way you try to have different behaviours with copying your workspace.
You should instead considering that CI will build and test as often as you want (each commit or every hour), but make reporting just one time (each midnight for example). You would be able to have faster continous builds, and correct documentation and reporting by night.
This is the way we work, and it is quite sufficient. We use jenkins for that, but you could trigger it with every CI soft I think) !
#hourly : mvn clean package (or install) --> from 1 to 5 minutes to run all test on all modules
#daily : mvn clean install site --> from 15 to 35 minutes to run all test on all modules + doc + reports + PDF reports
You can also use profiles to trigger different behaviours, but this is too much sophisticated for such a basic use.

Resources