We are trying to centralize the versions of all the artifacts that we are using in our code base to remove duplication and ease the task of bumping versions.
We have created a BOM pom with the versions of all of our artifacts and third party artifacts and imported it (scope import) in the dependencyManagement section of the poms of each of our artifacts.
To avoid having to update each artifact each time the bom version changes we have tried to use a version range when importing the bom.
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.acme</groupId>
<artifactId>bom</artifactId>
<version>[1.0,)</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
However maven does not seem to recognize version ranges in the dependencyManagement section of a pom.
I'm aware that if the relationship between our artifacts were hierarchical we could use modules and release from a parent POM. However unfortunately this is not the case.
This must be a common use case for maven. What are we doing wrong or what other solutions exist?
Taking into account the number of relevant issues in Maven issues tracker, it looks like it was a long-lasting issue in Maven.
Based on the most recent and relevant ticket, this will be resolved in the next major Maven release (4.0.0).
Related
We have module that uses DropWizard with Jetty, and it fails on startup with the error: "org/eclipse/jetty/util/thread/ExecutionStrategy$Factory"
java.lang.NoClassDefFoundError: org/eclipse/jetty/util/thread/ExecutionStrategy$Factory
at org.eclipse.jetty.io.SelectorManager.<init>(SelectorManager.java:52)
at org.eclipse.jetty.server.ServerConnector$ServerConnectorManager.<init>(ServerConnector.java:497)
at org.eclipse.jetty.server.ServerConnector.newSelectorManager(ServerConnector.java:229)
at org.eclipse.jetty.server.ServerConnector.<init>(ServerConnector.java:221)
at io.dropwizard.jetty.HttpConnectorFactory.buildConnector(HttpConnectorFactory.java:562)
at io.dropwizard.jetty.HttpConnectorFactory.build(HttpConnectorFactory.java:539)
at io.dropwizard.server.DefaultServerFactory.buildAppConnectors(DefaultServerFactory.java:234)
at io.dropwizard.server.DefaultServerFactory.buildRoutingHandler(DefaultServerFactory.java:194)
at io.dropwizard.server.DefaultServerFactory.build(DefaultServerFactory.java:172)
at io.dropwizard.cli.ServerCommand.run(ServerCommand.java:49)
at io.dropwizard.cli.EnvironmentCommand.run(EnvironmentCommand.java:44)
at io.dropwizard.cli.ConfiguredCommand.run(ConfiguredCommand.java:87)
at io.dropwizard.cli.Cli.run(Cli.java:78)
at io.dropwizard.Application.run(Application.java:93)
There are multiple modules in this project and there are 2 different jetty-io artifacts in the project, one with version: 9.3.20 and 9.4.18 (this is where SelectorManager is located, which tries to use the non-existing interface).
And for some reason it seems like that the older version (9.3.20, which is pulled by another module) gets to be on the classpath, and it tries to use the Factory interface within the ExecutionStrategy interface.
The ExecutionSrategy intervface is within the jetty-util artifact. And there are 2 versions of this artifact as well (9.4.18 and 9.3.19, the newer version does not have this Factory interface within ExecutionStrategy.
The result of mnv:dependency -Dverbose of the module where the error was thrown:
result of mvn command
I dont really know how to tackle this issue, the maven tree looks good, the good dependencies are being used from what I am seeing
Do not mix multiple versions of Jetty at the same time.
It might be a good idea to depend on the jetty-bom to force all jetty dependencies to be a specific version, no matter the transitive dependencies where they are coming from. (directly referenced dependencies will not use bom features)
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-bom</artifactId>
<version>9.4.28.v20200408</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
I just spend all day trying to figure out why I was not able to include FontawesomeFX to my Maven project. It turns out that the dependency to copy includes an extra line that prevented my maven eclipse project from downloading the dependency.
So why is <type>pom</type> included?
So why is <type>pom</type> included?
Perhaps an unsatisfying answer, but this looks like a bug in Bintray. The artifact is not of type pom, and the suggested syntax appears to be wrong. (The suggested Ivy snippet makes the same mistake.)
JFrog do not appear to have a public issue tracker to report this without a support contract, but they suggest using the artifactory tag.
For comparison, the Central Repository shows the correct form:
<dependency>
<groupId>de.jensd</groupId>
<artifactId>fontawesomefx</artifactId>
<version>8.9</version>
</dependency>
but doesn't include versions since 8.10.
On various projects I've been working on, I've seen diferent ways of specifying dependencies versions. On some projects, the package version is written on the same dependency declaration:
<dependency>
<groupId>org.apache.myfaces.extensions.validator.validation-modules</groupId>
<artifactId>myfaces-extval-property-validation</artifactId>
<version>2.0.7</version>
<scope>compile</scope>
</dependency>
On others, a property is used, as in:
<dependency>
<groupId>org.apache.myfaces.extensions.validator.validation-modules</groupId>
<artifactId>myfaces-extval-property-validation</artifactId>
<version>${versions.extval}</version>
<scope>compile</scope>
</dependency>
For multimodule projects, I can see a clear benefit in declaring versions on the parent pom to avoid duplication (and the potential confusion and errors that come with it), but on single module applications, would there be a benefit to use such a level of indirection?
What would be a best practice for this and why?
Thanks a lot :)
With a version property you can override it on the command line whereas with a fixed version you cannot.
So you can recompile your project with a newer version just by specifying it on the command line.
mvn -Dversions.extval=2.0.8 clean package
Or something.
apart from that, mostly used on multi-projects, and although there you have the dependency management section as well for versions.
I have a multimodule maven project, where module share dependencies. By share I mean use the same dependencies. However each module declares dependencies itself. To keep sanity (yeah, maven, sanity, I know), and to have all modules using the same version of dependencies, parent pom declares properties with version numbers:
<properties>
<dependency1.version>1.0-SNAPSHOT</dependency1.version>
<dependency2.version>1.1-SNAPSHOT</dependency2.version>
</properties>
and all modules use that like:
<dependency>
<groupId>group</groupId>
<artifactId>dependency1</artifactId>
<version>${dependency1.version}</version>
</dependency>
I'm quite happy with this setup, as it allows me to change dependencies versions in 1 place.
Now I have a bunch of dependencies that I maintain myself. Release of those is automatic and very simple, basically:
mvn release:prepare release:perform -B
now I want to automate further and in the main project I run:
mvn versions:update-properties
(basically I also run: "mvn versions:use-releases" to change usual dependencies if needed, but it's out of the scope of this question).
After this update-properties run, properties in my main projects pom point to releases (which is good). However if my modules use properties to define versions of other dependencies and those projects have newer versions available, those properties are also changed.
Is there any way to limit damage from update-properties? versions:use-release takes includes property, so I can use it only on mine artefacts. Cannot find anything similar for update-properties.
I can revert all poms besides parent one and commit/push only that, but it doesn't seem elegant.
It sounds that you didn't understand the concept of maven.
In such circumstances you should use dependencyManagement in the parent pom like the following:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>3.0</version>
</dependency>
...
</dependencies>
</dependencyManagement>
In you modules you just use a dependency like this:
<dependencies>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
</dependency>
...
</dependencies>
The important step is not to define the version. In this case the version will be used which is defined by the dependency management block. So you don't need to define properties etc. and furthermore you have a single point where you can define and change the dependencies in particular the versions.
Apart from that it's possible to limit the properties which will be changed defining it on the command line on the version:update-properties call.
I am new to Maven and am setting up my first maven project. I am also creating some maven assets in the form of some poms that can be inherited from or used as dependencies in any future projects as well. I want to group dependencies together and to be able to selectively add them to a project as needed.
I read this article on pom best practices. I like the idea of grouping related dependencies together into poms and then adding the pom as a dependency to a project as needed. This approach works great for compile scoped dependencies. However it fails for provided scoped ones since as transitive dependencies, they get omitted.
Here's an example of what I mean: Lets say I group together web dependencies for my projects into a web-deps pom.xml. These include compile scoped spring framework dependencies and also a provided scoped javaee one:
<modelVersion>4.0.0</modelVersion>
<groupId>com.xyz</groupId>
<artifactId>mvn-web-deps</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>javaee</groupId>
<artifactId>javaee-api</artifactId>
<version>${javaee.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
I then add this pom as a dependency in another project:
<modelVersion>4.0.0</modelVersion>
<groupId>com.xyz</groupId>
<artifactId>project-a</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependency>
<groupId>com.xyz</groupId>
<artifactId>mvn-web-deps</artifactId>
<version>0.0.1-SNAPSHOT</version>
<type>pom</type>
</dependency>
The dependencies in mvn-web-deps now become transitive. Since the dependency reference above is compile scoped, the provided transitive dependency gets omitted.
I want to avoid adding them to the dependency section of a parent since there can only be one parent and a project may need only some of these dependency groups, not all. I can perhaps add them to the dependencyManagement section, but then I will have to redeclare each dependency (sans the version) in each child project.
What is the correct/better way of grouping dependencies while avoiding the issues like above?
The short answer to your question is that you should only include 'provided' dependencies locally where the code requires it to compile, but not in parent pom.xml or other structures. Indicating that you have a 'provided' dependency in global pom.xml is non-sense for maven, because it does not need it to compile in such pom.xml.
Here is the long answer:
When I started using Maven, I had the same idea of trying to group artifacts and dependencies into pom.xml modules hoping they would be useful in the future. Now, that I have a bit more experience, I got to understand that it is a complete waste of time. For me, this was form of over-engineering.
I have learned to split my big projects into separate modules, each in their own subversion repository. I am including dependencies as necessary for each local module in their pom.xml. I release versioned tags of each module as I am coding and as necessary (i.e., when tested and stable).
I build my big projects by creating a separate maven project with its own pom.xml and import my modules as dependencies. From time to time, I update the module's version in the dependency when I have made a release. Then, I let maven do the job of pulling whatever it has to pull, transitively of not, when compiling/releasing the big project.
Maven allows all sorts of complex constructions and hierarchy between pom.xmls, but IMHO this feature creates unnecessary mess and complexities. So far it has not proved to be a real benefit for me. At the beginning, I was hoping that compiling one pom.xml would compile the rest properly in a cascading way. I did get some result, but what a mess to maintain in all the global pom.xml.
Releasing my module's artifacts separately and building my project on these releases has saved me so much time that I can only recommend it. In total, I have less pom.xml to maintain and they are also less complex. For the same final result...
So, if your only reason for building global/structural pom.xml is a hope to save time, I recommend abandoning this idea... Separate code in separate projects, release and THEN compile globally.
I concluded that Maven was not designed for this kind of use-case. I ended up having a parent pom.xml with all the libraries I use added to its <dependencyManagement> section. Any new projects/modules that I create have their pom.xml inherit from the parent pom.xml and add each dependency they need to their own <dependencies> section, minus the version. This scheme allows me to manage the versions for the libraries that I use and the respository declarations they need at a single place. Another advantage (over trying to create dependency bundles somehow) is that this gives more fine-grained control over the libraries added to child poms - only the dependencies that are actually needed are added.
Provided-scope dependencies are indeed inherited from parent POM, but NOT from POM defined as dependencies and I consider that a Maven weakness.
Given that Maven has also difficulties in adding modules as dependencies across module hierarchies, I can't say Maven is a sophisticated tool to manage multi-module projects. Maven expects a strict single-rooted hierarchy that is only suitable for the simplest projects.