We are attempting to move several multi-module applications to maven, and having some problems.
Each module is stored independently in cvs. We have manifest files for each application, which list the modules required for that application (and optionally the version). Not all modules are in maven form.
So application 'customer_care' has the following manifest:
<manifest>
<module id="MY_api"/>
<module id="custcare_webapp"/>
</manifest>
Similarly, the application 'core batch' has a manifest like this:
<manifest>
<module id="MY_api"/>
<module id="core"/>
<module id="batch"/><!--NB this is a non-maven module -->
</manifest>
I have started 'mavenising' our code, so the MY_api project has a pom.xml with dependencies defined, including one on another internal code module 'central_config'. I have specified version RELEASE.
The problem
This all works fine, until I need to create a frozen manifest. I can specify a version for each module:
<manifest>
<module id="MY_api" version="0.123.0"/>
<module id="core" version="0.456.0"/>
<module id="batch" version="0.789.0"/><!--NB this is a non-maven module -->
</manifest>
BUT this build is not reproducible, because the version of the 'centralconfig' dependency in MY_api is 'RELEASE'. So if someone releases a new version of 'centralconfig', then next time we build this frozen manifest, it's different.
So why don't we use hard-coded versions of dependencies like central-config? Because then, we would have to update perhaps 10 or 20 pom files every time someone updates centralconfig to a new version. Everything which depends on central config, and everything which depends on that, would need its pom.xml updating and to be re-released. Not only is this lots of work, I don't know how I could programmatically and reliably identify every module which declares a dependency on central config.
A possible solution?
Could I define 'centralconfig.version' in one place, and then refer to it in all my modules? If so, where should I do this? I don't know much about parent poms but I feel they might provide a solution.
Update
It seems that using a parent pom is the way to go. But according to this question: Can maven projects have multiple parents? , it's not possible for a maven child project to have multiple parents.
So then how can the MY_api module be a child of both custcare_webapp and core_batch?
Update
I've concluded that maven doesn't meet my requirements, and we've gone back to using our 12-year old home-grown solution build using ant and CVS.
One other option that is often better than a parent-structure for managing versions is to import dependencies.
To illustrate how this works you create one project that only contain a pom specifying the versions to use for all your modules:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>test</groupId>
<artifactId>module-versions</artifactId>
<packaging>pom</packaging>
<version>1.0</version>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>test</groupId>
<artifactId>a</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>foo</groupId>
<artifactId>bar</artifactId>
<version>2</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
Then, in all your projects that need to have dependencies to anyhing that you have hard coded versions for you import this project in the following manner:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>test</groupId>
<artifactId>module-versions</artifactId>
<version>1.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
This way you only have to change the module-versions project anytime you release a new version of anything you have a dependency to.
This way you can have multiple "module-versions"-projects to split things up a bit.
Of course, you still have the problem that all project's that want to use the new version must also be released in turn, but that is the cost of using released dependencies in Maven.
I think you do need a parent POM. That is a top-level pom.xml that is solely a POM module and has no associated code. You build the entire project by running the mvn command on this pom.xml.
The POM should be in the directory above all the module directories. That is, each of your modules will be in a subdirectory of the directory that holds the master pom.xml
This POM's <packaging> type will be pom. That means it's a POM-only project with no code of its own. It will also have a <modules> tag containing one <module> element for each of your modules. That way, when you run the mvn command, Maven will know to build each of these modules as well. A decent sample parent POM is here.
Set all your dependencies in this POM, using the standard <dependencies> tag. The module POMs will inherit them. (Update: see comments below, is definitely worth exploring the <dependencyManagement> tag instead for the parent POM.)
Finally, each of your module POMs should refer back to the master POM. That way, if you run mvn in one of the module directories (i.e you are just building one module), it will look to the parent for dependencies. You do this with a <parent> tag, which will hold the <groupid> and <artifactid> of the master POM. A good example of a <parent> tag, as well as a good overall review of multi-module projects, is here.
Related
I'm using a BOM to import dependencies from another project to mine, and I need a way to reference a dependency's version that is already declared in said BOM. So far, I've attempted to list the dependency version as a property in the BOM, but this approach fails because properties don't get imported with BOMs.
I've seen where the Dependency Plugin's dependency:properties goal does almost exactly what I need, but instead of giving me a full path of the artifact I need the version as a property. Is there something out there that can give me the version of a resolved artifact as a property?
UPDATE - 'Why not use a parent pom?'
I commonly find myself working in application server environments, where the dependencies provided are specified with BOM artifacts (as it appears that this has become a somewhat common/standard way to distribute groups of inter-related artifacts, i.e. widlfly). As such, I want to treat the BOM as the single source of truth. The idea of doing something like re-delcaring a dependency version property that has already been defined in a BOM seems incorrect.
If I were to define properties in a parent pom that mirrored an application server's environment, I now have to worry about keeping parent pom properties and BOM properties in sync - why even have a BOM at all at that point?
The information is already available on the dependency tree, it's just a matter of exposing it...
Couldn't find any existing maven or plugin functionality for this, so I forked the old dependencypath-maven-plugin and altered it to use versions. Now I can drop in a plugin like this:
<build>
.
.
<plugins>
.
.
<plugin>
<groupId>io.reformanda.semper</groupId>
<artifactId>dependencyversion-maven-plugin</artifactId>
<version>1.0.0</version>
<executions>
<execution>
<id>set-all</id>
<goals>
<goal>set-version</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
And access properties like this:
groupId:artifactId:type[:classifier].version
I.E.
io.undertow:undertow-core:jar.version=1.3.15.Final
Check out the README for more info on how to use the plugin. It's available # Maven Central:
<dependency>
<groupId>io.reformanda.semper</groupId>
<artifactId>dependencyversion-maven-plugin</artifactId>
<version>1.0.0</version>
</dependency>
... plugins all the way down ...
Short answer - yes, you can.
In details, your root pom.xml:
<properties>
<slf4j.version>1.7.21</slf4j.version>
</properties>
...
<dependencyManagement>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
...
</dependencyManagement>
In modules pom.xml:
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
...
</dependencies>
Also you can use ${slf4j.version} value to filter resources or in plugin configurations.
Update
In case you cannot use properties in the parent POM, you can either
retreive all dependencies and their versions with dependency:list plugin; or
use together dependency:list + antrun:run plugin; or
configure CI server scripts to do it for you (e.g. with this example); or
write a custom plugin to handle your versions logic.
This maven plugin is on Github (https://github.com/semper-reformanda/dependencyversion-maven-plugin) and it is a must for anyone dealing with Dependency versions, for instance when using Webjars dependencies - you can inject Webjar version numbers directly into your web resources.
I had been looking for such a functionality for a long time, I hope more people come across it and that it gets up on Maven central (I actually think it should come with Maven out of the box)
I have the a project pom and a parent pom. The parent pom defines a dependency as follows:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.mycode/groupId>
<artifactId>common</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
My project pom inherits the parent and defines the dependency.
<parent>
<groupId>au.com.truelocal</groupId>
<artifactId>truelocal-parent</artifactId>
<version>develop</version>
</parent>
<dependencies>
<dependency>
<groupId>com.mycode</groupId>
<artifactId>common</artifactId>
</dependency>
</dependencies>
I used to build with Maven this way without issue.
I now want to start having a different version in parent, common and project.
I am going to use the maven versions plugin to set my version.
I am setting the parent version and version successfully however, maven keeps looking for the wrong version of common. E.g. if my project is building as version 1.0.0-4 then it looks for common-1.0.0-4 but I actually need it to get the latest version of common instead which could be for example 1.0.0-23.
Can i use the versions plugin to adjust my dependency version? How do I make it only apply to common and not other dependencies I may have?
mvn versions:set (I guess this is what you've done) sets the version of your project, respectively the project versions which are part of a multi module project.
It doesn't touch the versions of the dependencies, either they are configured in a parent pom within <dependencyManagement> or within <dependencies>.
You can adjust the dependency versions by several ways: mvn versions:display-dependency-updates , mvn versions:use-latest-releases , mvn versions:use-latest-snapshots.
Use mvn versions:help or mvn versions:help -Ddetail=true -Dgoal=use-latest-snapshots to get more informations.
I have two projects I am working on which share some common code - I am putting this common code in to a new project called Core.
Both my projects use maven to build, and my core classes will also use maven. In Eclipse how do I configure maven to do a maven build of the core classes and then use these in the build for my two other applications?
Is there some prebuilt rule I need to specify - for example build this project, however, go build core first and use the output of that for this.
Hope that makes some sort of sense.
You can add a dependency to Core artifact in your project.
If you use M2E Eclipse plug-in, workspace artifacts are quite easy to reference in the Maven editor.
The only condition for this kind of dependency to work is that dependent artifact must be retrievable from a maven repository (eventually putting it to the local maven repository through install goal).
You could add a parent pom, with modules
<project>
<groupId>com.mypackage</groupId>
<artifactId>parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<name>parent</name>
<packaging>pom</packaging>
...
<modules>
<module>Core</module>
<module>MyModuleA</module>
<module>MyModuleB</module>
</modules>
...
</project>
And then just add your dependency in MyModuleA and MyModuleB like a normal dependency
<dependency>
<groupId>com.mypackage</groupId>
<artifactId>Core</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
I've got multi module maven project, where main project depend on sub-module. Every dependency of sub-module is define by version like this: ${pom.version}. I use maven release plug-in. If I try to prepare release, I've got an error about missing version of sub-module.
Example:
main pom is on version 1.0, I try to release it. Maven build every sub-module to version 1.1, then try to build parent, and then crash. Because it can't find sub-module-1.1.
I don't know how to tell maven to build, and immediate install to local-repo every sub-module witch it build. I use maven2.
My pom:
<modelVersion>4.0.0</modelVersion>
<groupId>com.voncuver</groupId>
<artifactId>voncuver</artifactId>
<packaging>pom</packaging>
<version>1.1-SNAPSHOT</version>
<name>multimodule</name>
<modules>
<module>mod1</module>
<module>mod2</module>
</modules>
(...)
<dependencyManagement>
<dependencies>
<dependency>
<artifactId>mod1</artifactId>
<groupId>com.voncuver</groupId>
<version>${pom.version}</version>
</dependency>
<dependency>
<artifactId>mod2</artifactId>
<groupId>com.voncuver</groupId>
<version>${pom.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
(...)
You should probably post a bit more of your project structure, but typically a multimodule project looks like this:
project
mod1
mod2
mod3
pom.xml
The main pom.xml would have "pom" packaging type, and have a section in it to build everything else:
<packaging>pom</packaging>
<modules>
<module>mod1</module>
<module>mod2</module>
<module>mod3</module>
</modules>
Then, the surest way to make sure things build properly is to execute:
mvn clean install
Without the "install", it's highly possible that things might not be found in the maven reactor, especially depending on what version of maven you are using (and a few other factors).
My goal is pretty simple actually but since there are multiple (and seemingly complex ways to do this) I wonder what I need to do... So I have certain runtime libraries (ADF libraries in particular) that are needed to be added to every project. This parent pom file will just have JAR dependencies in it. How can I use this pom file from a child pom file?
I don't think that using inheritance is a good solution here. Even if every project uses ADF artifacts, you don't want all poms to get these dependencies so declaring them in a corporate parent pom is not really an option.
So, instead, my recommendation would be to create a project with pom packaging to group the ADF dependencies together:
<project>
<groupId>com.mycompany</groupId>
<artifactId>adf-deps</artifactId>
<version>1.0</version>
<packaging>pom</packaging>
<dependencies>
<dependency>
<groupId>some.groupId</groupId>
<artifactId>adf-artifact-1</artifactId>
<version>${jdev.version}</version>
</dependency>
...
<dependency>
<groupId>some.groupId</groupId>
<artifactId>adf-artifact-n</artifactId>
<version>${jdev.version}</version>
</dependency>
</dependencies>
<properties>
<jdev.version>10.1.3</jdev.version>
</properties>
</project>
Then, install/deploy this project and declare it as dependency in any project that needs the ADF artifacts:
<project>
...
<dependencies>
...
<dependency>
<groupId>com.mycompany</groupId>
<artifactId>adf-deps</artifactId>
<version>1.0</version>
<type>pom</type>
</dependency>
</dependencies>
</project>
If the child POM file is actually a child (i.e. declares its parent), then it will inherit the dependencies and there is nothing left for you to do.