I have a Multi-Module Maven project. My parent POM has the following modules:
<module>common</module>
<module>ingest</module>
<module>package</module>
The package modules handles all aspects of building a deployable zip file using maven-antrun-plugin. The other two modules are where the core application code is located. Within the package I have various profiles holding the configuration settings for production, staging and development environments. Each profile looks like:
<profile>
<id>prod</id>
<properties>
<oozie.url>http://oozie-server:11000/oozie</oozie.url>
<stage.user>prod-stage</stage.user>
</properties>
</profile>
This works perfectly at the parent level, running:
mvn clean install -P prod
All the .properties file have the various properties expanded to be the ones in the Maven profile.
Within the ingest module, one class may rely upon a .properties file with the ingest module. The contents of this properties file will look something like:
stageUser=${stage.user}
When running tests for the ingest module, the properties are not expanded to be the properties from the build profile e.g. the property will still be stageUser=${stage.user} rather than stageUser=prod-stage. This causes the test to fail.
The only workaround I have is to add in the required profiles and properties to get the test to pass into the ingest POM. This means I have these properties in two locations both the package and ingest modules. Is there a better solution to this?
The inheritance of properties from the parent should work. Make sure you have the parent declaration in the child modules:
<parent>
<artifactId>parent</artifactId>
<groupId>parentGroupId</groupId>
<version>version</version>
</parent>
Related
I got a Maven project with the following structure:
Module A (parent), Submodule B and Submodule C
In the parent pom.xml I am using a variable for settings the version of all projects:
...
<version>${revision}</version>
...
<properties>
<revision>1.1</revision>
</properties>
...
<modules>
<module>moduleB</module>
<module>moduleC</module>
</modules>
</project>
Module C is my distribution package which uses the shade plugin for packaging everything into one single jar.
In the submodules I set the parent like this:
<parent>
<groupId>group</groupId>
<artifactId>moduleA</artifactId>
<version>${revision}</version>
</parent>
Now I want to use Module C in another project, however I only get the following error when doing so:
Failed to execute goal on project newProject: Could not resolve dependencies for project group:newProject:jar:0.0.1-SNAPSHOT: Failed to collect dependencies at group:moduleC:jar:1.1: Failed to read artifact descriptor for group:moduleC:jar:1.1: Could not find artifact group:parent:pom:${revision} in nexus (NEXUS_URL)
I assume the problem is, that the variable value is not filled in when referencing Module C as dependency. How can I solve this issue? I already tried to clean the project before building and forcing to update all artifacts without success.
Maven expects all modules to have a hard version.
To avoid editing lots of poms, use the versions plugin, example:
mvn versions:set -DnewVersion=1.0.1
If you run the above command on the parent it will fix all the child poms.
See here for documentation.
Thanks to the comment of hadu.mansouri I could fix it. I used flatten-maven-plugin for flattening the pom.xml files. However, it seems to have a problem with the shade plugin, as the shaded module was the only module where it did not work. Thus, in the released shade module pom it said:
<version>${revision}</version>
for referencing the parent. I used the approach of the article linked in the comment. There, this extension was used: https://github.com/jcgay/unique-revision-maven-filtering
Using this instead of the flatten-maven-plugin, Maven builds the multi module project correctly with the single version property, and I can also use the shaded module in other projects properly.
Background: Most of my Java project have a lot of boiler-plate configuration that I end up writing into my POM. (For example the sourceEncoding is always UTF-8, the organization details never change). To save having to copy-paste blocks of configuration I've created my own standard 'parent' POM I can extend for each of my projects.
I also have a number of tools that I use in every Java project I work on (e.g. checkstyle, PMD etc) so I've added the plug-ins for each tool into my standard parent pom.
PMD (and a few other tools) have an interesting problem - they requires a set of configuration files to operate correctly. Since Maven prefers to work with the concept of 'one deployable resource per module' I've created the following (simplified) structure:
<My Template>
|--- Config Files
\--- Parent Pom
My Template: is a maven controlled project with two modules
Config Files: is a maven module that bundles the PMD config files into a ZIP and deploys them to a maven repo
Parent Pom: is all my boiler plate code. It has a dependency on "Config Files" and is set up to extract the configuration from the ZIP
So far so good....
The Requirment: "Parent Pom" and "Config Files" are always built and deployed together - that is "Parent Pom" version 1.2.3 will only ever work with "Config Files" version 1.2.3, so when I write the dependency in "Parent POM" I need to do something like:
<dependency>
<groupId>org.my-org</groupId>
<artifactId>config-files</artifactId>
<version>${project.version}</version>
<type>zip</type>
<scope>test</scope>
</dependency>
The Problem: When I come to start my application (let's say version 0.0.1) I use "Parent Pom" as my parent. Maven will calculate the effective POM for the project and ${project.version} will be interpreted as 0.0.1 (the application version) rather than 1.2.3 (the parent POM version). Maven then fails to find the config files.
The Question: How can I tell Maven to "Give me version for POM xxx"?
What I really don't to do is creating additional properties that are in lockstep with ${project.version} because I can guarantee that we'll forget to update it when we Bump the POMs for a release!
There are a few things you can do.
You can use ${project.parent.version} instead of ${project.version}.
But probably a better way would be to define pluginManagement and/or dependencyManagement in your parent pom - with appropriate versions and configuration. In you child projects you just "use" the "managed" version/configurations in dependencies or build/plugins without specification of concrete versions or configuration.
For example see the org.sonatype.oss:oss-parent POM which is widely used in open-source projects.
I have 3 maven modules. One is the parent grouping the other 2 modules.
All project folders are on the same root level.
Though the deployment is not working. What's wrong with the following configuration?
project-parent/pom.xml
project-commons/pom.xml
project-web/pom.xml
parent-pom:
<project>
<groupId>de.myproject</groupId>
<artifactId>project-parent</artifactId>
<packaging>pom</packaging>
<modules>
<!-- <module>../project-commons</module> -->
<module>../project-web</module>
</modules>
</project>
web-pom:
<parent>
<groupId>de.myproject</groupId>
<artifactId>project-parent</artifactId>
<version>1.0.0</version>
<relativePath>../project-parent/pom.xml</relativePath>
</parent>
Result:
[ERROR] The project de.myproject:project-parent:1.0.0 has 1 error
[ERROR] Child module \project-parent\..\project-web\pom.xml of \project-parent\pom.xml does not exist
The project structure:
svn/project-commons/trunk/pom.xml
svn/project-web/trunk/pom.xml
svn/project-parent/pom.xml
I will outline an approach that I have used successfully on large and small projects that may meet your needs.
pom.xml
superpom/pom.xml
utils0/pom.xml
utils1/pom.xml
utils2/pom.xml
services0/pom.xml
services1/pom.xml
services2/pom.xml
war0/pom.xml
war1/pom.xml
In this example, the utils and services modules produce jars; the war modules produce wars. There would be various dependencies between the utils, services and wars.
The superpom modules is of type pom and just contains the parent pom. Each of the util/service/war pom.xml refer to the parent with the relative path of ../superpom:
<parent>
<groupId>mygroup</groupId>
<artifactId>superpom</artifactId>
<version>1.3.3.3-SNAPSHOT</version>
<relativePath>../superpom</relativePath>
</parent>
The superpom/pom.xml does NOT contain any elements and does not refer to the "child" modules/poms in any way. The superpom contains shared properties, plugin configs, dependency versions, etc. It is a big pom. All the other module's poms are (generally) small.
The top-level pom contains the references to all the other modules (including superpom). It does not have a parent pom (at least not one that lives within this project hierarchy). You use the top-level (not superpom) to build everything. You can use profiles (or other means) to control which modules you want to build, but I have generally just built the whole tree from here. Support for SCM, CI builds, etc. lives in this top-level pom, which keeps all your other projects (including the parent pom) clean and concerned only with building and testing the artifacts.
I don't have any concept of "trunk" in my maven structure - that is an orthogonal concept. If I want to work on trunk or a branch, I check out the appropriate one and always have the same maven structure.
I use this to build my spring mvc app:
mvn clean package
I use the maven war plugin to create a war file, but the problem I am facing is that in my resources folder I have my development versions of my .properties files for log4j etc.
When I push to production, and run:
java -jar ...
It explodeds the war file, and then at that point I can modify the .properties files with my production settings, but I obviously want to do this during my maven build for production.
Is there a way I can tell maven that this is a production build, so get these files from somewhere else? And during development, keep doing what it is doing now?
User maven profiles. Maven profiles help you in specifying different properties for different profiles. So you can have two profiles - development and production.
Something like this -
<profiles>
<profile>
<id>development</id>
<!-- we'll properties here... -->
</profile>
<profile>
<id>production</id>
<!-- ...and here -->
</profile>
</profiles>
Like this example -
<profile>
<id>development</id>
<properties>
<db.driverClass>oracle.jdbc.driver.OracleDriver</db.driverClass>
<db.connectionURL>jdbc:oracle:thin:#127.0.0.1:1521:XE</db.connectionURL>
</properties>
</profile>
<profile>
<id>production</id>
<properties>
<db.driverClass>oracle.jdbc.driver.OracleDriver</db.driverClass>
<db.connectionURL>jdbc:oracle:thin:#134.0.0.1:3124:XE</db.connectionURL>
</properties>
</profile>
There are a couple of options here. The first (as others have mentioned as well) is to use maven profiles. Instead of having multiple version of your properties files, you would have something like:
mypropsfile.properties
-----------------------
prop1=${prop1.val}
prop2=${prop2.val}
Then in your profiles, you can define values for those properties (make sure you have resource filtering enabled for this to work. see an example http://www.manydesigns.com/en/portofino/portofino3/tutorials/using-maven-profiles-and-resource-filtering).
You can also have your properties file have production values in it but with the ability to override those files in development. Spring profiles are helpful for this. For example, in development mode you can look for a properties file named <user-home>/mypropertiesoverride.properties, which could be used to override any of the production value properties with development specific ones.
I prefer the second method here where you have a default properties file and then you can just override select properties.
I have the following projects organized in a flat structured way:
parentProject
+-pom.xml
projectWeb <depends on libraryA and libraryB>
+-pom.xml
libraryA
+-pom.xml
libraryB
+-pom.xml
The pom.xml inside the parentProject has references to the other modules and its used for inheritance and dependencyManagement, here is a snippet:
<project>
....
<modules>
<module>../projectWeb</module>
<module>../libraryA</module>
<module>../libraryB</module>
</modules>
<dependencyManagement>
...
</dependencyManagement>
<build>
...
</build>
....
</project>
In Jenkins I have one maven job for each project, and it works fine when I build the parentProject, ie. builds every project referenced in the modules section.
The problem that I have is when I commit to the SVN a change in libraryA, I would expect that after building libraryA, a rebuild to projectWeb to be launched, but that didn't happen.
Anyone knows what am I doing wrong?
Thanks in advance.
EDIT
When I remove the modules section from parentProject\pom.xml, it works as espected, but I loose the aggregation advantage of having a parent pom.
It looks like you're asking your parent POM to do two things:
Set up dependency management stuff
Aggregate your build
It's generally better if you split this out into two poms - a parent pom for #1 and an aggregate pom for #2. You'd then have something like..
[root dir] aggregate pom.xml
+ /parent
+ /web
+ /libA
+ /libB
See this answer for more details: https://stackoverflow.com/a/3301162/211993
You'd then configure Jenkins to check out the root dir and run "mvn clean install"
This should be configured in jenkins job. See "libraryA job"/"Configuration"/"Build Triggers"/"Build after other projects are built"