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

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>

Related

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.

Is there a way to put common stuff of multiple child poms into one single place?

say I have some child poms, which share 90% in common. I want to put their common code into a common place. I can't use a common parent because these child poms needs to extend from their own parents as well. Is there other place I can put common stuff, define once, and let the child poms to share, instead of copying the common stuff multiple times in each child pom? Or if you have other opinion, please suggest as you pleased. Thank you
e.g.
Project A has poms
<groupId>project-a</groupId>
<artifactId>parent</artifactId>
<version>1.0</version>
and
<groupId>project-a</groupId>
<artifactId>parent</artifactId>
<version>2.0</version>
Project B implemented by a totally different team has this parent pom
<groupId>project-b</groupId>
<artifactId>parent</artifactId>
<version>0.1</version>
<modules>
<module>child-extends-from-project-a-version-1.0</module>
<module>child-extends-from-project-a-version-2.0</module>
</modules>
and some child projects that extend from Project A
<parent>
<groupId>project-a</groupId>
<artifactId>parent</artifactId>
<version>1.0</version>
</parent>
<groupId>project-b.child</groupId>
<artifactId>child-extends-from-project-a-version-1.0</artifactId>
"some common stuff"
<parent>
<groupId>project-a</groupId>
<artifactId>parent</artifactId>
<version>2.0</version>
</parent>
<groupId>project-b.child</groupId>
<artifactId>child-extends-from-project-a-version-2.0</artifactId>
"some common stuff"
How do I group those "common stuff" in one place without repeating in each child pom?
(I deleted my old answer, because I misread your question, sorry)
There is way, but it is a little bit cumbersome. Since the long planned Maven fragments are not yet implemented, you could use the tiles-maven-plugin:
https://github.com/maoo/maven-tiles
The Tiles plugin allows you to "import" foreign poms into your model. So you would create a separate pom for your "common stuff":
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>common</groupId>
<artifactId>common-stuff</artifactId>
<packaging>pom</packaging>
<version>1.0</version>
<name>"Common Stuff"</name>
"Common stuff"
</project>
In your actual child POMs, you include the tiles plugin as extension (possibly in your true parent pom):
<build>
<plugins>
<plugin>
<groupId>it.session.maven.plugins</groupId>
<artifactId>tiles-maven-plugin</artifactId>
<version>${maventiles.plugin.version}</version>
<extensions>true</extensions>
</plugin>
</plugins>
</build>
Now you can import your common stuff using properties (I am not quite happy with using properties for this, but it works):
<properties>
<tile.1>common:common-stuff:1.0</tile.1>
</properties>
As a result, your effective POM contains elements from your child project itself as well as from the imported common-stuff artifact.
The plugin is somewhat proprietary, but for normal usecases, it works quit well.

Is there a way to cascade the version of a parent pom?

I have a root pom.xml that acts as a parent for several child pom.xml files, which is great if you have one or two child pom.xml files. I am working on a project that has 50+ child pom.xml files, and several releases going on at once. Everything is great until I need to update the version of the parent pom.xml files, which can be tedious. Is there a way to cascade the version of the parent pom.xml down to all child pom.xml files?
I had the idea to just create a property in the parent pom.xml for the current version, but that's not working.
EDIT
Here is a sample from my child pom.xml files:
<parent>
<groupId>myGroup</groupId>
<artifactId>myArtifactId</artifactId>
<version>1.0</version> <!-- This is the value that I would like to parameterize in my child pom.xmls -->
<relativePath>../../pom.xml</relativePath>
</parent>
As an aside, I am using Maven 3.0.3
You can do it this way:
Have an aggregator POM project, in which you specify all your child modules and then run this goal on the this aggregator project:
mvn versions:update-parent
This will update all child modules with the new parent version.
Alternatively you can use the same before each release:prepare goal of your child module, thus avoiding creating the aggregator module.
So in case you want to release a child module, you just run this goal:
mvn versions:update-parent release:prepare
This will ensure that the parent gets updated with a new version before it is being prepared for a release.
I read in your comment you are missing an scm tag. Example of usage in case of subversions might be:
<scm>
<developerConnection>scm:svn:https://your.domain/scm/svn/yourModule/trunk/</developerConnection>
</scm>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<configuration>
<tagBase>https://your.domain/scm/svn/yourModule/tags</tagBase>
</configuration>
</plugin>
</plugins>
</build>
Release plugin does not work without a properly configured scm.
You do not need to configure the tagbase tag in release plugin in case you follow "trunk, tags, branches" best practice in your svn repository, see this answer.
I assume you having a thing like this:
+--root (pom.xml)
+--- module1 (pom.xml)
+---
In the root pom.xml:
<project ..>
<groupId>the.company.project</groupId>
<artifactId>the-artifact</artifactId>
<version>1.0-SNAPSHOT</version>
...
</project>
whereas in the childs you should have:
<project ..>
<parent>
<groupId>the.company.project</groupId>
<artifactId>the-artifact</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>the-artifact-child</artifactId>
</project>
For such purposes you should use the maven-release-plugin which handles the updating of the version in root as well in childs. If you don't use maven-release-plugin you can use the versions-maven-plugin which can handle the same things.
I had the same problem and what I did was slightly different than anything suggested so far. Assume that your project has the following folder structure:
parent
+-- child1
+-- child2_of_parent
+-- child3_of_parent
+-- child4
+-- child5_of_child4
Do note that except for child5_of_child4, all the rest of the projects have as parent the top level project parent. This is regardless of the folder structure.
Parent pom.xml:
<groupId>...</groupId>
<artifactId>...</artifactId>
<version>1.1-SNAPSHOT</version>
All children pom.xml except for child5_of_child4 that has as parent child4:
<parent>
<groupId>...</groupId>
<artifactId>parent</artifactId>
<version>1.1-SNAPSHOT</version>
<relativePath>../parent</relativePath>
</parent>
You go to the parent directory and change its version from version from 1.1-SNAPSHOT to 1.2-SNAPSHOT. Then you do (more details here):
mvn versions:update-child-modules
As this is not recursive, it only works on the direct children of your parent project. In other words, all sub-modules will be updated to point to parent 1.2-SNAPSHOT except for child5_of_child4.
In your child pom.xml:
<parent>
<groupId>groupId</groupId>
<artifactId>parent.artifactId</artifactId>
<version>version</version>
<relativePath>../parent-pom</relativePath>
</parent>
<artifactId>child.artifactId</artifactId>
Just don't put the version in the child poms. It's inherited automatically. It will show up as a warning in Eclipse plugin if you edit there.

Defer properties evaluation in Maven sub-modules

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>

Maven versioning of multi-module projects with parent POM

This is a slightly different version of this previous question, in that I have separate multi-module and parent POMs: In a Maven project, how can I automatically update the version all child modules, plus the parent?
I am trying to update my POMs to go from a development snapshot version to a released version number. I have googled the issue to death, tried the release and version plug-in, and nothing seems to be able to handle my fairly simple setup.
Following published Maven best practices, and trying not to duplicate information when I can avoid to, I ended up with the structure below for my multi-module project.
There is a single version defined by the common pom-parent.xml; and B depends on A.
I find it a bit surprising that the standard plug-ins can't handle what seems to be a fairly basic setup, am I missing something?
None of the workarounds I have come up with are completely satisfactory:
define the product version as a property is a bit flaky, the same module source could get different versions because of a user settings.xml or other trick
merge the root pom.xml and pom-parent.xml and move the product-wide build steps I currently maintain in the root pom into a dedicated module; and hope that the std plug-ins will then work... not tried.
Any suggestion?
root/pom-parent.xml: parent of all the POMs below
<project...>
<groupId>acme</groupId>
<artifactId>ParentPom</artifactId>
<packaging>pom</packaging>
<version>1.0.0-SNAPSHOT</version>
root/pom.xml: multi-module projects with A and B as submodules
<project ...>
<parent>
<groupId>acme</groupId>
<artifactId>ParentPom</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<groupId>acme</groupId>
<artifactId>Product</artifactId>
<packaging>pom</packaging>
<modules>
<module>A</module>
<module>B</module>
</modules>
root/A/pom.xml:
<project ...>
<parent>
<groupId>acme</groupId>
<artifactId>ParentPom</artifactId>
<relativePath>../parent-pom.xml</relativePath>
<version>1.0.0-SNAPSHOT</version>
</parent>
<groupId>acme</groupId>
<artifactId>A</artifactId>
<packaging>jar</packaging>
root/B/pom.xml:
<project ...>
<parent>
<groupId>acme</groupId>
<artifactId>ParentPom</artifactId>
<relativePath>../parent-pom.xml</relativePath>
<version>1.0.0-SNAPSHOT</version>
</parent>
<groupId>acme</groupId>
<artifactId>B</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>acme</groupId>
<artifactId>A</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
</dependencies>
If you have a structure like the following:
root
+-- pom.xml (1.0-SNAPSHOT)
!
+-- module1
! +-- pom.xml (1.0-SNAPSHOT)
+-- module2
+-- pom.xml (1.0-SNAPSHOT)
all modules (module1 and module2) using root as their parent like this:
<parent>
<groupId>xxx</groupId>
<artifactId>xxx</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
If you want to factor out other default setup like pluginManagement or dependencyManagement for other projects as well you have to use a separate parent pom which must be a separate maven project which contains only the pom.xml. Furthermore this project will be deployed and released separately. If you do so you can use this as parent in the root pom of the above structure.
If you like to make a release you will go simply into the root folder of the above structure and the version number etc. will automatically incremented.
mvn -B release:prepare release:perform

Resources