Automatic resolve dependency hierarchy for a custom jar - java

I am struggling with the maven dependencies. The maven dependency hierarchy is not resolved in my projects where I add my custom build jar. This is a little bit confusing, because all the dependencies of other externally provided dependencies (like org.json, reasteasy-jaxrs ) are nicely shown in the dependency hierarchy view.I am using Eclipse EE IDE for Web Developers with maven plugin.
The project structure: The project is a platform consisting of several services using the same project-support module. Further, the project-support will be used in external projects (here project-consumer) as well.
project-parent (pom)
project-support (jar)
project-service-a (war)
project-service-b (jar)
project-consumer (war)
project support (jar)
Extract of project-parent.pom
<modules>
<module>../project-support</module>
<module>../project-serviceA</module>
<module>../project-serviceB</module>
</modules>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<tomcat.version>7.0.50</tomcat.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-catalina</artifactId>
<version>${tomcat.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.6.3</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20140107</version>
<scope>provided</scope>
</dependency>
</dependencies>
</dependencyManagement>
Extract of project-support.pom
<parent>
<groupId>com.somecompany.project</groupId>
<artifactId>project-parent</artifactId>
<version>1.1.0-SNAPSHOT</version>
<relativePath>../project-parent</relativePath>
</parent>
<artifactId>project-support</artifactId>
<name>projectsupport</name>
<dependencies>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-catalina</artifactId>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
</dependency>
</dependencies>
Extract of project-service-a.pom
<parent>
<groupId>com.somecompany.project</groupId>
<artifactId>project-serviceA</artifactId>
<version>1.1.0-SNAPSHOT</version>
<relativePath>../project-parent</relativePath>
</parent>
<artifactId>project-service-a</artifactId>
<name>projectsupport</name>
<dependencies>
<dependency>
<groupId>com.somecompany.project</groupId>
<artifactId>project-support</artifactId>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.1</version>
</dependency>
</dependencies>
So, when looking at the project-serviceA dependency hierarchy (and also in the effective pom), the required dependencies of project-support are not included which results in code compilation errors. Further the project-support is used in projects outside the scope of project-parent.
So my question: Why does maven not resolve the dependencies tree of project-support and adds them into the effective pom?
Thanks in advance.

You have set the scope of the dependencies to provided in you parent's dependency management section. According to the introduction to the dependency mechanism, the dependency scope is used to limit the transitivity of a dependency.
The above linked introduction also includes a table that declares which scopes play in the transitivity game and which do not. The provided scope is not part of the transitivity.
So the solution is to not declare any scope in the dependency management but declare a reasonable scope in the dependency usage.

Related

Inheriting the version of an optional dependency

My company has 3 Maven projects organized as follows:
Project A depends on Project B.
Project B depends on Project C. (Project B has set Project C as an Optional dependency in their POM)
I am the owner of Project A. I would like to add Project C as a direct dependency in my POM. However, I do not want to be responsible for keeping the version of Project C up to date. Is there a way I can inherit the version of Project C specified in Project B's POM at all times?
If you don't control project B, it's not possible, except possibly with some plugin hackery.
If you do control project B then you can declare a dependency management section in that project which you can additionally import into project A.
Project B POM
<dependencyManagement>
<groupId>com.foo</groupId>
<artifactId>project-c</artifactId>
<version>1.2.3</version>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.foo</groupId>
<artifactId>project-c</artifactId>
<!-- no need for version here, comes from dependencyManagement -->
<optional>true</optional>
</dependency>
</dependencies>
Project A POM
<properties>
<!-- using a property isn't necessary, but ensures the
POM import and dependency stay in sync -->
<project.b.version>2.3.4</project.b.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.foo</groupId>
<artifactId>project-b</artifactId>
<version>${project.b.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.foo</groupId>
<artifactId>project-b</artifactId>
<version>${project.b.version}</version>
</dependency>
<dependency>
<groupId>com.foo</groupId>
<artifactId>project-c</artifactId>
<!-- version is not necessary, imported from project-b's dependency management -->
</dependency>
</dependencies>
This will mean Project A will default to Project B for all dependencies in B's dependency management section. I don't think there's a way to restrict it to just a specific one. I doubt you'll care but just something to be aware of.
Any versions that Project A defines, either in its own dependency management or directly in <dependencies>, will override any version brought in from Project B's dependency management.

How to determine the <parent> dependency for a set of springframework dependencies

I like to know if below is possible and how.
I was following a tutorial for spring boot and it was mentioned there we can have a parent dependency.
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.6.RELEASE</version>
</parent>
And then define the dependencies without the version number.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
This will add the dependencies version 1.5.6.RELEASE of spring-boot-starter and spring-boot-starter-web in to the projects dependencies.
Just like that I want to find what is the <parent> code snippet for the following dependencies I need to add in to a new project.
Dependencies in <groupId>org.springframework</groupId>. I need to use the version 4.3.9.RELEASE.
spring-context
spring-jdbc
spring-test
Thanks!
If you are using Spring Boot then these three dependencies will be provided for you by the following starters:
spring-test will be provided by spring-boot-starter-test
spring-context will be provided by spring-boot-starter-data-jpa
spring-jdbc will be provided by spring-boot-starter-jdbc
So, with the following parent:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.6.RELEASE</version>
</parent>
... if you add these dependencies:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
... then you will get
spring-context
spring-jdbc
spring-test
However, Spring Boot 1.5.6.RELEASE depends on v4.3.10.RELEASE of those core Spring libraries not 4.3.9.RELEASE as suggested in your question. Typically, you would accept Spring's curation of dependencies so if Sping provides 4.3.10.RELEASE then either (a) you should use that version or (b) downgrade Spring Boot toa version which provides 4.3.9.RELEASE.
Read on for details on how to identify the correct starter for a given curated library ...
The spring-boot-starter-parent is a special starter that provides useful Maven defaults and a dependency-management section which defines numerous dependencies which you might want to use in your POM. These dependencies are often referred to as "curated" or "blessed" and since they are defined in a dependency-management section somewhere in the maven hierarchy you can refer to them in your POM without a version tag (i.e. they inherit the version from the dependency-management section entry.)
You can see the spring-boot-starter-parent POM here and peeking inside you can see that it references the spring-boot-dependencies POM here.
Looking at your question you mentioned that you can declare a dependency like so ...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
... this is because the spring-boot-dependencies POM declares the following:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${revision}</version>
</dependency>
So, the parent and the starters are just a means of wrapping up dependency declarations and making them easier for application developers to use. The Spring docs summarise this as:
Starters are a set of convenient dependency descriptors that you can include in your application. You get a one-stop shop for all the Spring and related technologies that you need without having to hunt through sample code and copy-paste loads of dependency descriptors. For example, if you want to get started using Spring and JPA for database access, include the spring-boot-starter-data-jpa dependency in your project.
However, this does not mean that all dependencies must be declared via parents or starters so, if you are not using Spring Boot then you can declare a dependency without using a parent or a starter and what you have described in your question (declaring dependencies on 3 core Spring libraries) can be safely covered by simply depending on those 3 libraries explicitly. For example, just add the following to your your pom.xml:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.3.9.RELEASE</version>
<scope>test</scope>
</dependency>
Since you are going though the tutorials I'm assuming you are new to spring.
The folks at spring were nice enough to setup a site that generates projects.
It is very easy to use. I recommend trying that while learning. Download a few apps with the dependencies you want and look at how they are set up.
Once you are comfortable and want to dive deeper, read #glytching's answer again, it is very good.
Use spring-framework-bom if you don't use Spring Boot and need Spring Framework dependencies only:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
<version>4.3.9.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
In such case dependency would be without version was specified:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
Also, yet another option exists if you use Spring Boot but you don't want to use spring-boot-starter-parent as parent artifact:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.5.9.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
See Spring Boot docs for more details. An important note from the docs:
Each release of Spring Boot is associated with a base version of the Spring Framework so we highly recommend you to not specify its version on your own.
It means that you should use Spring Framework version is defined for Spring Boot.

Maven Dependency Version As Property

I have a maven pom file that defines a dependency as such:
<dependencies>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.3.6</version>
</dependency>
</dependencies>
It is often said that everything in the pom can be referenced as a Maven property:
https://bowerstudios.com/node/991
For example, you can read ${project.version}, ${project.build}, etc. Is there a way to read a dependency's version as a Maven property, ala ${project.dependencies.dependency.groupId=org.apache.httpcomponents&artifactId=httpclient.version} ?
You could define a custom property under <properties> and refer to it from your dependency. Preferred way is to place the property in parent pom (if exist and is a multi module project). Alternately, you can skip the <version> altogether if you had defined the <dependency> in <dependency-management> section
<properties>
<http.client.version>4.3.6</http.client.version>
</properties>
...
<dependencies>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>${http.client.version}</version>
</dependency>
</dependencies>

Eclipse Maven Dependency issue

I have maven-depenencies folder which lists over 50+ jars I need for compile and testing on my local. In addition POM.xml have specific (see snippet) which lists the dependencies I wanted in "target/final_build.jar". I do not want rest of maven - dependencies I can see on eclipse IE. I just want following packaged as aprt of final jar..
What is the easy way to accomplish . I tried copy-dependencies but it copied all Maven dependencies and not the 4 listed in pom.xml. More over they are copied over to lib/src folder.
Desired state is to just have 4 dependencies mentioned below are part of "target/outputfile.jar"
<dependencies>
<dependency>
<groupId>org.twitter4j</groupId>
<artifactId>twitter4j-core</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>org.twitter4j</groupId>
<artifactId>twitter4j-stream</artifactId>
<version>3.0.3</version>
</dependency>
</dependencies>
Dependencies that are needed for compile/test but not for the application (because the (EE-/JDK-/?-) Container already have this classes) can be specified by the dependency scope provided:
<dependencies>
<dependency>
<groupId>org.twitter4j</groupId>
<artifactId>twitter4j-core</artifactId>
<version>3.0.3</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.twitter4j</groupId>
<artifactId>twitter4j-stream</artifactId>
<version>3.0.3</version>
<scope>provided</scope>
</dependency>
</dependencies>

Maven - moved code to new artifact; transitive dependencies issue

Here is my situation:
I created a new artifact in a library called 'web-ng-framework', and moved code into it from an old artifact in the library, 'web'
I deleted the 'web' artifact
And here is the problem:
ProjectA uses an older version of the library, and so it has a compile dependency on 'web'
ProjectB depends on ProjectA
ProjectB uses the latest version of the library, so when ProjectB is built, it contains both the 'web' and 'web-ng-framework' libraries, causing a possible conflict
Does anyone know how I can solve this? Thanks!
EDIT:
Would doing 'relocation' of 'web' to 'web-ng-framework' maybe work better? In ProjectA, I could include a dependency on 'web' so that Maven would see that what it really needs is 'web-ng-framework'. Would that work?
When including ProjectA in ProjectB exclude web. Like this
<dependency>
<groupId>your.group</groupId>
<artifactId>projectA</artifactId>
<exclusions>
<exclusion>
<groupId>your.group</groupId>
<artifactId>web</artifactId>
</exclusion>
</exclusions>
</dependency>
A classic solution to this problem is the 'Version 99' hack.
To do this, use the following in your root pom:
<dependencyManagement>
<dependency>
<groupId>your.group</groupId>
<artifactId>web</artifactId>
<version>99.0-does-not-exist</version>
</dependency>
</dependencyManagement>
Then put an empty web-99.0-does-not-exist.pom and web-99.0-does-not-exist.jar in your repository.
This ensures that every project that inherits from this root pom will not get the old version of the web.jar anymore.
I suggest that you use optional dependencies
This can be acheived by making web depencency optional in projectA.
<project>
<groupId>some.group</groupId>
<artifactId>projectA</artifactId>
...
<dependencies>
<!-- declare the dependency to be set as optional -->
<dependency>
<groupId>some.group</groupId>
<artifactId>web</artifactId>
<version>1.0</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
</dependencies>
</project>
When declaring some other project that depends on projectA the web dependency will not be included.
<project>
<groupId>some.group</groupId>
<artifactId>projectB</artifactId>
...
<dependencies>
<dependency>
<groupId>some.group</groupId>
<artifactId>projectA</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>some.group</groupId>
<artifactId>web-ng-framework</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</project>
Now projectB will only have a dependency on projectA and web-ng-framework, not web.

Categories