Maven: How to import dependency of type pom? - maven

I am trying to migrate a java application to maven. There are some dependencies which have been provided as jar files so far. One of these dependencies is jung2, which is available from the maven repository: mvnrepository.com
I need all of the provided modules and I do not understand how to declare this dependecy correctly in my pom.xml such that all corresponding jar files are downloaded and the classes are available at compile time.
This is what my pom.xml file looks like right now:
<?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>groupId</groupId>
<artifactId>myProject</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencyManagement>
<dependencies>
<!-- https://mvnrepository.com/artifact/net.sf.jung/jung2 -->
<dependency>
<groupId>net.sf.jung</groupId>
<artifactId>jung2</artifactId>
<version>2.0.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
I also tried leaving out <scope>import</scope> and put the dependency into the dependencies section. When executing mvn compile or mvn package, error message occur that the corresponding packages do not exist.
If I additionally add a dependency inside dependencies but outside of dependencyManagement, e.g.
<dependencies>
<dependency>
<groupId>net.sf.jung</groupId>
<artifactId>jung2</artifactId>
</dependency>
I receive an error about missing version. But as far as I understood, this should not be necessary due to dependencyManagement? If I also add <version>2.0.1</version>, then I get the following error message:
Failure to find net.sf.jung:jung2:jar:2.0.1

The dependencyManagement tag is used generally when you have a multi module project in maven (where you will have parent-child relationship).
If you specify any dependencies within the dependencyManagement tag, it would NOT actually download the dependencies.
Putting the dependency within this tag simply means that this dependency is available (to download / to use) for the child pom. The child pom will have to explicitly provide the groupId and the artifactId co-ordinates to download and use the jar to compile its classes.
If you just have a single module project (looks like yours is a single module project) then you can fix this issue by not using the dependencyManagement tag.
Simply put your jars in the dependencies tag.
For ex:
<dependencies>
<dependency>
<groupId>com.abc</groupId>
<artifactId>def</artifactId>
<version>1.0.0</version>
<type>pom</type> // This will now download the pom and its associated transitive dependent jars
</dependency>
<dependency>
<groupId>com.pqr</groupId>
<artifactId>xyz</artifactId>
<version>1.0.0</version>
<type>pom</type> // This will now download the pom and its associated transitive dependent jars
</dependency>
</dependencies>
Like I said before, the dependencyManagement tag will mostly make sense to use if you have a multi-module project, which isn't your case.

Related

Maven POM packaging with dependencies

I'm trying to construct a codebase where subsystems can be developed as maven modules, without the importing POM needing to concern itself with the internal structure of the maven module.
The "importing" pom
<project>
<artifactId>application</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<artifactId>submodule-1</artifactId>
</dependency>
</dependencies>
</project>
The "imported" pom
<project>
<artifactId>submodule-1</artifactId>
<packaging>pom</packaging>
<modules>
<module>api</module>
<module>implementation</module>
</modules>
<dependencies>
<dependency>
<artifactId>api</artifactId>
</dependency>
<dependency>
<artifactId>implementation</artifactId>
</dependency>
</dependencies>
</project>
This does seem to work, at least partially; the generated JARs appear to be on the classpath during mvn package. IntelliJ shows the application has a dependency on submodule-1 and transitively on api and implementation. However, mvn dependency:tree fails while building submodule-1 saying
Could not resolve dependencies for project submodule-1:pom:1.0.0-SNAPSHOT: Could not find artifact api:jar:1.0.0-SNAPSHOT
I'm trying to determine if this is a valid pattern, that of having packaging of pom, with defined dependencies which are also defined modules in the POM.
Have I stumbled upon a working-but-not-supported edge case, or is the dependency plugin broken in some way, or I'm breaking it in some way, or something else?

Maven: pin dependency version where dependency is managed by a BOM

We use a Maven BOM to manage dependencies of a suite of libraries. The dependencyManagement section of the BOM generally uses version ranges to specify versions of these libraries, e.g., [2.0,2.1) Child pom.xml's using the BOM do not specify versions for these managed dependencies. (Edit for clarification: we use specific versions for third party dependencies, the ranges are used for internal libraries that are undergoing development, where the versions can change rapidly. We define version ranges to ensure broad compatibility between these libraries, i.e. all within the same major version.)
(Note that this is not a multi-module project. Libraries and service projects using the BOM mechanism just declare it as a parent and pull it from a Nexus repository. they are not built together.)
We also have some build system scripts that use versions:resolve-ranges to pin the versions of dependencies appearing in our library and service pom.xml's (not the BOM's pom.xml). These pom.xml's with resolved ranges are checked in to source control and tagged, so that if we need to roll back a deployment to an earlier version, we can use that tagged pom.xml to make a build that uses the same dependency versions as the original build, even if a newer version of a dependency is now available (and thus resolve-ranges would come up with the newer version if we reran it).
I just noticed that these two mechanisms are not working well together. Running versions:resolve-ranges on the library or service pom.xml only resolves the ranges in that pom.xml. Versions under dependency management are still not specified, so if we made a new build using this pom.xml, we'd get the latest dependency version in range at build time. Not what we want!
Is there a way to use versions:resolve-ranges (or any other plugin or technique) to resolve the managed versions and stick them into the child pom.xml?
Here is a contrived example.
The BOM:
<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>
<groupId>com.maventest</groupId>
<artifactId>myproject</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<name>myproject</name>
<url>http://maven.apache.org</url>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>[2.0, 2.3]</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
Child project using the BOM (one managed dependency, one unmanaged):
<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">
<parent>
<groupId>com.maventest</groupId>
<artifactId>myproject</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../myproject/pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.maventest</groupId>
<artifactId>mytest</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>mytest</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>[3.8, 3.9)</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Snippet from mvn dependency:tree showing effective versions of dependencies:
[INFO] com.maventest:mytest:jar:1.0-SNAPSHOT
[INFO] +- commons-lang:commons-lang:jar:2.3:compile
[INFO] \- junit:junit:jar:3.8.2-brew:test
Dependency section from mytest pom.xml after mvn versions:resolve-ranges:
<dependencies>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.2-brew</version>
<scope>test</scope>
</dependency>
</dependencies>
So the unmanaged dependency is resolved, as expected. But the managed one is not. How can I get it to be resolved too?
Forgot about this question! In the end I could never find a way to pin the managed versions which were based on ranges. So I did stop defining the versions in the BOM and just specified them with ranges in each child pom. More boilerplate in the child poms, but not that bad.
We were still able to define properties that specified the ranges in the BOM which the children could use, making it a bit easier to bump all the ranges all when necessary.

How does Maven handle transitive dependencies inherited from parent?

Given the parent and child pom below and lib1 and lib2 both include the class foo.bar.Test.
parent pom
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>foo</groupId>
<artifactId>foo-parent</artifactId>
<version>1.0</version>
<dependencies>
<dependency>
<groupId>my.transitive</groupId>
<artifactId>lib1</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</project>
child pom
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>foo</groupId>
<artifactId>foo-parent</artifactId>
<version>1.0</version>
</parent>
<artifactId>foo-child</artifactId>
<dependencies>
<dependency>
<groupId>my.transitive</groupId>
<artifactId>lib2</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</project>
If I include foo-child as a dependency in myApp and instantiate foo.bar.Test, which version of the class would Maven resolve to? And why?
my app pom
<project>
<modelVersion>4.0.0</modelVersion>
<artifactId>myApp</artifactId>
<groupId>myApp</groupId>
<version>1.0</version>
<dependencies>
<dependency>
<groupId>foo</groupId>
<artifactId>foo-child</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</project>
The short answer would be: it depends on which one is found on the classpath first.
Having 2 of the same classes packaged with an application is not ideal as it can lead to many difficult to debug errors... If your myApp project is just going to be a jar then it would be best to compile it using the same library as what is going to be available to it at runtime.
I believe maven uses the order it is written to the pom to build. One way of looking at this would be to run the following command for myApp:
mvn dependency:tree -Dverbose
This will print the dependencies in the order that they should appear on the classpath per spec. You can always use exclusions to exclude any inherited library you might not want. Hope this helps.

Building project with maven containing other projects

I have a web-project A dependent on project B,
Project B dependent on JAR C
the problem:
When I package the web-project A, there is a jar for b (expected), but their is no reference to jar c
So, when I run my web-project A and access function the project B do I got class NotFoundException because jar C is not included
Any help how can I include jar C in parent project A without writing it myself in project A pom.xml
web-project pom.xml
<project ....>
..........
<dependencies>
<!--Local Projects -->
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>project B</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
</project>
project B pom.xml
<project ....>
<dependencies>
<dependency>
<groupId>jar_C</groupId>
<artifactId>jar_C</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
As your configuration, Maven is just responsible for the compilation, that is to say a jar won't take any of its dependencies with itself. If you need to wrap up the dependencies all together, you should use the Assembly plugin, see:here
Have a read at the Maven Dependency Mechanism
import (only available in Maven 2.0.9 or later)
This scope is only used on a dependency of type pom in the <dependencyManagement> section. It indicates that the specified POM should be replaced with the dependencies in that POM's <dependencyManagement> section. Since they are replaced, dependencies with a scope of import do not actually participate in limiting the transitivity of a dependency.
So Basically, try this
web-project pom.xml
<project ....>
..........
<dependencies>
<!--Local Projects -->
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>project B</artifactId>
<version>1.0.0</version>
<scope>import</scope>
</dependency>
</dependencies>
</project>

Dependeny Management using POM import

I am creating a project 'test-jar' in my local and i am using pom file which I don't have write access as Parent of 'test-jar' project. The parent project has already defined depedencyManagement with old versions.
As I have to update dependency versions in my project and planning to override parent's dependency Management. So, I have created another POM file with my own dependency Management and imported into 'test-jar' project.
My Project :
<project>
<artifactid>test-jar</artifactid>
<parent>
<artifactId> test-parent </artifactId>
</parent>
<dependencies>
<dependency>
<artifactId>jar/artifactId>
</dependency>
<dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<artifactId>custom-pom</artifactId>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencyManagement>
</project>
My Parent Project:
<project>
<artifactid>test-parent</artifactid>
<dependencyManagement>
<dependencies>
<dependency>
<artifactId>jar/artifactId>
<version>1.0</version>
</dependency>
</dependencyManagement>
</project>
My Custom POM for updated dependencyManagement:
<project>
<artifactid>custom-pom</artifactid>
<dependencyManagement>
<dependencies>
<dependency>
<artifactId>jar</artifactId>
<version>3.0</version>
</dependency>
</dependencyManagement>
</project>
The problem is, I am always getting dependency version from parent pom, though i have imported new dependency management in project.
I am using Maven 2.2.1 version here.
Is there any solution how to overwrite Dependency Management from Parent POM ?
Based on the documentation:
This scope is only used on a dependency of type pom in the
section. It indicates that the specified POM
should be replaced with the dependencies in that POM's
section. Since they are replaced, dependencies
with a scope of import do not actually participate in limiting the
transitivity of a dependency.
Apart from your problem you can simply use differerent version which are different of the onses defined in the parent pom's dependencyManagement. Furthermore you could create a separate pom wich defines the dependencies with new version (dependencyManagement) and inherits from the given parent.

Resources