Maven not resolving given nested dependency version - java

I have given following module in module A:
<dependencies>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.9.2</version>
</dependency>
</dependecies>
And included module A in module B like:
<dependencies>
<dependency>
<groupId>com.example.test</groupId>
<artifactId>A</artifactId>
<version>1.01</version>
</dependency>
</dependecies>
But still mvn dependency:tree is showing 3.14.9 version in module B, please help.
[INFO] com.example.test:B:jar:1.01
[INFO] +- com.example.test:A:jar:1.01:compile
[INFO] | +- com.squareup.okhttp3:okhttp:jar:3.14.9:compile
I have also excluded it from all other modules that have 3.14.9 conflicts.
I know I can add okhttp 4.9.2 explicitly in module B but there are many such modules, I don't want to add explicitly 4.9.2 version each time.
For some reason, this is the case only for okhttp, rest other dependencies resolving given version

I don't see the version of artefact A you are trying to use in module B, can you check if it's the same version you are trying to build using okhttp 4.9.2

I solved the dependency resolution by enforcing dependency version in dependencyManagement in parent pom as mentioned in https://stackoverflow.com/a/2684291/5859017 in 2nd point. Maybe some dependency in parent pom was causing problem that has okhttp as transitive dependency.

Related

Maven dependencies wrong version for okhttp3 mockwebserver

I am trying to use okhttp3.mockwebserver with my Spring boot project and I find out that okhttp3:mockwebserver:jar:3.14.9 is included instead of 4.9.1.
I have created small 'mock' projects to reproduce the issue I have in my prod.
The project is here https://github.com/mkarasik/okhttp-test
It contains two folders:
lib
This is a simple library including mockwebserver as dependency
pom.xml dependency
<dependencies>
...
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>mockwebserver</artifactId>
<version>4.9.1</version>
<exclusions>
<exclusion>
<artifactId>junit</artifactId>
<groupId>junit</groupId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
Maven dependencies tree
\- com.squareup.okhttp3:mockwebserver:jar:4.9.1:compile
+- com.squareup.okhttp3:okhttp:jar:3.14.9:compile
This is already wrong. Mockwebserver pom contains 4.9.1 okhttp artifact, however 3.14.9 is shown in tree
project
Simple Spring Boot app including lib project
<dependency>
<groupId>com.example</groupId>
<artifactId>lib</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>test</scope>
</dependency>
Maven dependencies tree
\- com.example:lib:jar:0.0.1-SNAPSHOT:test
\- com.squareup.okhttp3:mockwebserver:jar:3.14.9:test
\- com.squareup.okhttp3:okhttp:jar:3.14.9:test
\- com.squareup.okio:okio:jar:1.17.2:test
The same problem is here. okhttp3:mockwebserver:jar:3.14.9 is included instead of 4.9.1 as it is specified in my lib pom.xml.
Is there anything I am missing in my xml configuration?
Found it it it is described in Introducing dependencies in other projects causes Maven to downgrade okhttp3 version
<properties>
<okhttp3.version>4.9.1</okhttp3.version>
</properties>
Fixes the issue
OkHttp provides a Maven BOM you can use to ensure a consistent version
https://github.com/square/okhttp#releases
Also, we have a bill of materials (BOM) available to help you keep
OkHttp artifacts up to date and be sure about version compatibility.
This example is gradle, but you it is originally a feature from maven.
https://docs.gradle.org/6.2/userguide/platforms.html#sub:bom_import
dependencies {
// define a BOM and its version
implementation(platform("com.squareup.okhttp3:okhttp-bom:4.9.3"))
// define any required OkHttp artifacts without version
implementation("com.squareup.okhttp3:okhttp")
implementation("com.squareup.okhttp3:logging-interceptor")
}

Why are SLF4J Logger and LoggerFactory imports missing from maven project? [duplicate]

What is the difference between dependencyManagement and dependencies?
I have seen the docs at Apache Maven web site.
It seems that a dependency defined under the dependencyManagement can be used in its child modules without specifying the version.
For example:
A parent project (Pro-par) defines a dependency under the dependencyManagement:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8</version>
</dependency>
</dependencies>
</dependencyManagement>
Then in the child of Pro-par, I can use the junit:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>
However, I wonder if it is necessary to define junit in the parent pom? Why not define it directly in the needed module?
I'm fashionably late to this question, but I think it's worth a clearer response than the accepted one (which is correct, but doesn't emphasize the actual important part, which you need to deduce yourself).
In the parent POM, the main difference between the <dependencies> and <dependencyManagement> is this:
Artifacts specified in the <dependencies> section will ALWAYS be included as a dependency of the child module(s).
Artifacts specified in the <dependencyManagement> section, will only be included in the child module if they were also specified in the <dependencies> section of the child module itself. Why is it good you ask? Because you specify the version and/or scope in the parent, and you can leave them out when specifying the dependencies in the child POM. This can help you use unified versions for dependencies for child modules, without specifying the version in each child module.
Dependency Management allows to consolidate and centralize the management of dependency versions without adding dependencies which are inherited by all children. This is especially useful when you have a set of projects (i.e. more than one) that inherits a common parent.
Another extremely important use case of dependencyManagement is the control of versions of artifacts used in transitive dependencies. This is hard to explain without an example. Luckily, this is illustrated in the documentation.
The documentation on the Maven site is horrible. What dependencyManagement does is simply move your dependency definitions (version, exclusions, etc) up to the parent pom, then in the child poms you just have to put the groupId and artifactId. That's it (except for parent pom chaining and the like, but that's not really complicated either - dependencyManagement wins out over dependencies at the parent level - but if have a question about that or imports, the Maven documentation is a little better).
After reading all of the 'a', 'b', 'c' garbage on the Maven site and getting confused, I re-wrote their example. So if you had 2 projects (proj1 and proj2) which share a common dependency (betaShared) you could move that dependency up to the parent pom. While you are at it, you can also move up any other dependencies (alpha and charlie) but only if it makes sense for your project. So for the situation outlined in the prior sentences, here is the solution with dependencyManagement in the parent pom:
<!-- ParentProj pom -->
<project>
<dependencyManagement>
<dependencies>
<dependency> <!-- not much benefit defining alpha here, as we only use in 1 child, so optional -->
<groupId>alpha</groupId>
<artifactId>alpha</artifactId>
<version>1.0</version>
<exclusions>
<exclusion>
<groupId>zebra</groupId>
<artifactId>zebra</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>charlie</groupId> <!-- not much benefit defining charlie here, so optional -->
<artifactId>charlie</artifactId>
<version>1.0</version>
<type>war</type>
<scope>runtime</scope>
</dependency>
<dependency> <!-- defining betaShared here makes a lot of sense -->
<groupId>betaShared</groupId>
<artifactId>betaShared</artifactId>
<version>1.0</version>
<type>bar</type>
<scope>runtime</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
<!-- Child Proj1 pom -->
<project>
<dependencies>
<dependency>
<groupId>alpha</groupId>
<artifactId>alpha</artifactId> <!-- jar type IS DEFAULT, so no need to specify in child projects -->
</dependency>
<dependency>
<groupId>betaShared</groupId>
<artifactId>betaShared</artifactId>
<type>bar</type> <!-- This is not a jar dependency, so we must specify type. -->
</dependency>
</dependencies>
</project>
<!-- Child Proj2 -->
<project>
<dependencies>
<dependency>
<groupId>charlie</groupId>
<artifactId>charlie</artifactId>
<type>war</type> <!-- This is not a jar dependency, so we must specify type. -->
</dependency>
<dependency>
<groupId>betaShared</groupId>
<artifactId>betaShared</artifactId>
<type>bar</type> <!-- This is not a jar dependency, so we must specify type. -->
</dependency>
</dependencies>
</project>
There's still one thing that is not highlighted enough, in my opinion, and that is unwanted inheritance.
Here's an incremental example:
I declare in my parent pom:
<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
</dependency>
</dependencies>
boom! I have it in my Child A, Child B and Child C modules:
Implicilty inherited by child poms
A single place to manage
No need to redeclare anything in child poms
I can still redelcare and override to version 18.0 in a Child B if I want to.
But what if I end up not needing guava in Child C, and neither in the future Child D and Child E modules?
They will still inherit it and this is undesired!
This is just like Java God Object code smell, where you inherit some useful bits from a class, and a tonn of unwanted stuff as well.
This is where <dependencyManagement> comes into play. When you add this to your parent pom, all of your child modules STOP seeing it. And thus you are forced to go into each individual module that DOES need it and declare it again (Child A and Child B, without the version though).
And, obviously, you don't do it for Child C, and thus your module remains lean.
It's like you said; dependencyManagement is used to pull all the dependency information into a common POM file, simplifying the references in the child POM file.
It becomes useful when you have multiple attributes that you don't want to retype in under multiple children projects.
Finally, dependencyManagement can be used to define a standard version of an artifact to use across multiple projects.
Sorry I am very late to the party.
Let me try to explain the difference using mvn dependency:tree command
Consider the below example
Parent POM - My Project
<modules>
<module>app</module>
<module>data</module>
</modules>
<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
</dependencies>
</dependencyManagement>
Child POM - data module
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
</dependencies>
Child POM - app module (has no extra dependency, so leaving dependencies empty)
<dependencies>
</dependencies>
On running mvn dependency:tree command, we get following result
Scanning for projects...
------------------------------------------------------------------------
Reactor Build Order:
MyProject
app
data
------------------------------------------------------------------------
Building MyProject 1.0-SNAPSHOT
------------------------------------------------------------------------
--- maven-dependency-plugin:2.8:tree (default-cli) # MyProject ---
com.iamvickyav:MyProject:pom:1.0-SNAPSHOT
\- com.google.guava:guava:jar:19.0:compile
------------------------------------------------------------------------
Building app 1.0-SNAPSHOT
------------------------------------------------------------------------
--- maven-dependency-plugin:2.8:tree (default-cli) # app ---
com.iamvickyav:app:jar:1.0-SNAPSHOT
\- com.google.guava:guava:jar:19.0:compile
------------------------------------------------------------------------
Building data 1.0-SNAPSHOT
------------------------------------------------------------------------
--- maven-dependency-plugin:2.8:tree (default-cli) # data ---
com.iamvickyav:data:jar:1.0-SNAPSHOT
+- org.apache.commons:commons-lang3:jar:3.9:compile
\- com.google.guava:guava:jar:19.0:compile
Google guava is listed as dependency in every module (including parent), whereas the apache commons is listed as dependency only in data module (not even in parent module)
There are a few answers outlining differences between <depedencies> and <dependencyManagement> tags with maven.
However, few points elaborated below in a concise way:
<dependencyManagement> allows to consolidate all dependencies (used at child pom level) used across different modules -- clarity, central dependency version management
<dependencyManagement> allows to easily upgrade/downgrade dependencies based on need, in other scenario this needs to be exercised at every child pom level -- consistency
dependencies provided in <dependencies> tag is always imported, while dependencies provided at <dependencyManagement> in parent pom will be imported only if child pom has respective entry in its <dependencies> tag.
If the dependency was defined in the top-level pom's dependencyManagement element, the child project did not have to explicitly list the version of the dependency. if the child project did define a version, it would override the version listed in the top-level
POM’s dependencyManagement section. That is, the dependencyManagement version is only
used when the child does not declare a version directly.
Just in my own words, your parent-project helps you provide 2 kind of dependencies:
implicit dependencies : all the dependencies defined in the <dependencies> section in your parent-project are inherited by all the child-projects
explicit dependencies : allows you to select, the dependencies to apply in your child-projects. Thus, you use the <dependencyManagement> section, to declare all the dependencies you are going to use in your different child-projects. The most important thing is that, in this section, you define a <version> so that you don't have to declare it again in your child-project.
The <dependencyManagement> in my point of view (correct me if I am wrong) is just useful by helping you centralize the version of your dependencies. It is like a kind of helper feature.
As a best practice, your <dependencyManagement> has to be in a parent project, that other projects will inherit. A typical example is the way you create your Spring project by declaring the Spring parent project.
The difference between the two is best brought in what seems a necessary and sufficient definition of the dependencyManagement element available in Maven website docs:
dependencyManagement
"Default dependency information for projects that inherit from this one. The dependencies in this section are not immediately resolved. Instead, when a POM derived from this one declares a dependency described by a matching groupId and artifactId, the version and other values from this section are used for that dependency if they were not already specified."
[ https://maven.apache.org/ref/3.6.1/maven-model/maven.html ]
It should be read along with some more information available on a different page:
“..the minimal set of information for matching a dependency reference against a dependencyManagement section is actually {groupId, artifactId, type, classifier}. In many cases, these dependencies will refer to jar artifacts with no classifier. This allows us to shorthand the identity set to {groupId, artifactId}, since the default for the type field is jar, and the default classifier is null.” [https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html ]
Thus, all the sub-elements (scope, exclusions etc.,) of a dependency element--other than groupId, artifactId, type, classifier, not just version--are available for lockdown/default at the point (and thus inherited from there onward) you specify the dependency within a dependencyElement. If you’d specified a dependency with the type and classifier sub-elements (see the first-cited webpage to check all sub-elements) as not jar and not null respectively, you’d need {groupId, artifactId, classifier, type} to reference (resolve) that dependency at any point in an inheritance originating from the dependencyManagement element. Else, {groupId, artifactId} would suffice if you do not intend to override the defaults for classifier and type (jar and null respectively). So default is a good keyword in that definition; any sub-element(s) (other than groupId, artifactId, classifier and type, of course) explicitly assigned value(s) at the point you reference a dependency override the defaults in the dependencyManagement element.
So, any dependency element outside of dependencyManagement, whether as a reference to some dependencyManagement element or as a standalone is immediately resolved (i.e. installed to the local repository and available for classpaths).
I do not recommend using dependencyManagement.
The only benefit of using it is that you can define the version in parent pom and do not need to define it again in child pom. But if you have a set of projects (especially micro-service projects). Using dependencyManagement has no benefits.
Different projects may need different dependency. Why inherit it from the same parent pom. Keep it as simple as possible. If one project needs A dependency, then add it to the pom file. Don't confuse developers.
In Eclipse, there is one more feature in the dependencyManagement. When dependencies is used without it, the unfound dependencies are noticed in the pom file. If dependencyManagement is used, the unresolved dependencies remain unnoticed in the pom file and errors appear only in the java files. (imports and such...)
One use case of <dependencyManagement> is for resolving library versions conflict.
Example:
Project A have library x:1.0.1
Project A have B library
B library have library x:1.0.0
Having this set you will get conflict having project A both x:1.0.1 and x:1.0.0.
To resolve this you can put dependency with specific version into <dependencyManagement> tag
If you have a parent-pom anyways, then in my opinion using <dependencyManagement> just for controlling the version (and maybe scope) is a waste of space and confuses junior developers.
You will probably have properties for versions anyways, in some kind of parent-pom file. Why not just use this properties in the child pom's? That way you can still update a version in the property (within parent-pom) for all child projects at once. That has the same effect as <dependencyManagement> just without <dependencyManagement>.
In my opinion, <dependencyManagement> should be used for "real" management of dependencies, like exclusions and the like.
It was explained by here to be easy to understand.
The conclusion difference between dependencyManagement & dependencies are declaration and actually addition

Override library version in Spring

I have the spring-ws-security dependency in a Spring Boot 2.1.7 project:
<dependency>
<groupId>org.springframework.ws</groupId>
<artifactId>spring-ws-security</artifactId>
</dependency>
Internally, the spring-ws-security pom has this dependency:
<dependency>
<groupId>org.apache.wss4j</groupId>
<artifactId>wss4j-ws-security-dom</artifactId>
<version>${wss4j.version}</version>
<exclusions>
...
</exclusions>
</dependency>
The parent of spring-ws-security is spring-ws, whose pom has a property:
<wss4j.version>2.2.0</wss4j.version>
I am trying to override this property in my pom file:
<properties>
<wss4j.version>2.2.4</wss4j.version>
...
</properties>
But it keeps taking the original 2.2.0 version:
$ mvn dependency:tree | grep wss4j
[INFO] | +- org.apache.wss4j:wss4j-ws-security-dom:jar:2.2.0:compile
[INFO] | | \- org.apache.wss4j:wss4j-ws-security-common:jar:2.2.0:compile
It takes the 2.2.4 version only if I explicitly supply the dependencies:
<dependency>
<groupId>org.apache.wss4j</groupId>
<artifactId>wss4j-ws-security-dom</artifactId>
<version>2.2.4</version>
</dependency>
<dependency>
<groupId>org.apache.wss4j</groupId>
<artifactId>wss4j</artifactId>
<version>2.2.4</version>
<type>pom</type>
</dependency>
Isn't overriding the property enough? Am I doing something wrong?
Here there are two points to consider:
One if you want to override the version in the properties in pom.xml, then your pom should have a parent-child relationship
second is if you want to use a particular version then we need to
declare the required version in your pom.xml explicitly and may
exclude the dependency from the third party jar and do a mvn clean install
Here is more information on dependency management and properties in maven
As I know, if you leave it blank without define any version. it will get the newest version of its library. So, you are right if you want to override the newest version to old version or certain version, by put the specific version. Have you trying to "mvn clean install" for that project?

Maven transitive has compile scope though its in provided scope in dependency management

This is how my application POM looks and it uses a custom framework built on top of spring called myframework. Since it runs on websphere, and the core libraries are available as shared library in run time, I want to only package web library into my WAR. Though I have my shared library dependency defined with provided scope, and added the shared library BOM containing all the core libraries defined in provided scope. One of the transitive dependency which is part of core library slf4j is coming in compile scope, and it gets packaged inside the war, which I don't expect to happen. There are many core dependency like this which are getting into compile scope. Why is this happening?
Based on this post Maven transitive dependency has scope compile while when dependency has provided scope
My core library should be in provided scope, as I have imported a BOM which has all this core library defined in provided scope but that is not happening. I have also provided the maven dependency tree below. Please advice.
Note: I am involved in the development of the framework and I don't want to directly include all of the core jar in dependencymanagement section in provided scope in the application, as there are lot of libraries and I don't want each developers using this framework to be aware of all the core jars, and include them in dependencymanagement section instead want them to use a BOM/POM.
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.myframework</groupId>
<artifactId>myframework-shared-libs-bom</artifactId>
<version>${library.version}</version>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.myframework</groupId>
<artifactId>myframework-shared-libs</artifactId>
<version>${library.version}</version>
<type>pom</type>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.myframework</groupId>
<artifactId>myframework-web-libs</artifactId>
<version>${library.version}</version>
<type>pom</type>
</dependency>
</dependencies>
Maven Dependency tree
+- com.myframework:myframework-shared-libs:pom:4.0.0-SNAPSHOT:provided
| \- org.slf4j:jcl-over-slf4j:jar:1.7.6:provided
\- com.myframework:myframework-web-libs:pom:4.0.0-SNAPSHOT:compile
\- com.myframework:myframework-web:jar:4.0.0-SNAPSHOT:compile
\- com.myframework:myframework-core:jar:4.0.0-SNAPSHOT:compile
\- org.slf4j:slf4j-api:jar:1.7.21:compile

Maven aggregation module serving as a bulk dependency

Is it possible to use an aggregating module (pom that aggregates modules for building purposes) as a dependency that transitively includes its modules as dependencies? Considering it must declare those dependencies that correspond to its submodules, otherwise if you declare it as a dependency, it hasn't own dependencies, so that no transitive deps are included.
I already tried it but I got a cyclic dependency error.
Otherwise I would have to create an extra module (say my_module_deps) that just declares all those dependencies, so I could use it as a dependency that transitively includes its dependencies. I don't like having maven modules that do not have any specific purpose except for being a dependency bulk.
This is the desired state, so I can use it for both module aggregation and a dependency to be used for getting its transitive dependencies :
<project>
<artifactId>aggregationModule</artifactId>
<modules>
<module>a</module>
<module>b</module>
<module>c</module>
</modules>
<dependencies>
<dependency>
<artifactId>a</artifactId>
</dependency>
<dependency>
<artifactId>b</artifactId>
</dependency>
<dependency>
<artifactId>c</artifactId>
</dependency>
</dependencies>
</project>
Do any of the sub-modules have that aggregating project defined as its parent?
If so, this cannot work, since for being parent the project must be build first.
But if the parent itself defines the modules as dependencies at the same time, the modules must be build first, so you created your cyclic dependency error.
You cannot declare a dependency to a project with packaging type "pom". If you do so maven will show the same error as when you declare a dependency to a jar module which does not exists in your local repository and could not be downloaded from your repository list.
Maybe some of the alternatives proposed to this question could help you.

Categories