How Maven and Java handle duplicated dependencies [closed] - java

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I do have some random issues within my application. And I suspect that the problem may arise from external dependencies. Let me elaborate.
My application is using an external jar with requests classes. Inside one of my projects, I had added the newest version of this library. But as you probably suspect, I have more dependencies than just one. And unfortunately, one of these dependencies has the same library which I added already, but with an older version. So at this moment, when I am firing mvn dependecy:tree, simplified results look like that:
+-my_project
+-request_lib.jar:1.5.0
+-required_lib.jar:1.0.0
+-random.jar:1.0.0
+-request_lib.jar:1.2.0
//more libs
//more libs
As you can see, what I need is the newest version of request_lib.jar:1.5.0, and at this moment no one can update required_lib.jar:1.0.0, and change the version or request inside of it.
How does Java handle this situation? Lets say inside of this project I am using request GetPlayerDataRequest, and in the newest version someone added a new field to this called String playerTitle. Will Java always use classes from the newest version? Or will it be mixed?
Because from what I see, sometimes users have fatal errors, where in logs we can find that method setPlayerData does not exist. I know that I can exclude the old jar in the pom. But I would like to know how it is handled by Java.

You want to use Maven's <dependencyManagement> feature. This is one of the most misunderstood and poorly documented areas of Maven and yet also one of its most powerful features.
In your pom.xml, if you have a <dependencyManagement><dependencies> section, then anything that is a child of it will apply all the way down the dependency tree, regardless of where else that dependency may be specified. (You can also include non-existing entries; if they designate a dependency that is not actually used anywhere by you or any of your transitive dependencies, then they are ignored.)
So, for example, if you want to ensure that the following dependency is used everywhere in your project no matter how it is "pulled in" or by whom:
<dependency>
<groupId>com.foo</groupId>
<artifactId>bar</artifactId>
<version>32</version>
</dependency>
…then if you add that entry to your pom.xml's <dependencyManagement><dependencies> section—even if your project itself doesn't use it, but your transitive dependencies do—so that it looks like this:
<dependencyManagement>
<dependencies>
<!-- other entries might go here -->
<!-- force version 32 of com.foo:bar no matter how it gets pulled into your project -->
<dependency>
<groupId>com.foo</groupId>
<artifactId>bar</artifactId>
<version>32</version>
</dependency>
<!-- other entries might go here -->
</dependencies>
</dependencyManagement>
…then that will do the trick.
A related thing that is not exactly documented anywhere is: dependency versions in "regular" <dependencies> entries (so <dependency> elements that do not appear as children of <dependencyManagement><dependencies> but only as children of <dependencies>) are suggestions. They are used only if an overriding <dependencyManagement> entry does not exist (which many times, of course, it does not).

Maven applies a dependency mediation mechanism, guaranteeing that only one of the two versions of the dependency gets bundled. So, in this case, Java doesn't have to handle anything really.
Relevant documentation: https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html

Java allows you to load different versions of the same class by using classloaders.
Using your example, you would load classes from request_lib.jar using one classloader, and required_lib.jar from another.
The topic is too extensive for a stackoverflow answer, there are many tutorials online.

Related

Java 9 ORMLite conflict in module-info

I have a Java 9 (or higher) project in which I want to include ORMLite with a H2 database. Therefore I need the two maven dependencies
<dependency>
<groupId>com.j256.ormlite</groupId>
<artifactId>ormlite-core</artifactId>
<version>5.1</version>
</dependency>
<dependency>
<groupId>com.j256.ormlite</groupId>
<artifactId>ormlite-jdbc</artifactId>
<version>5.1</version>
</dependency>
...
(+ the h2 dependency.)
Since I am using Java 9 I have to add them to my module-info.java:
module my.module {
exports my.package.to.export;
requires ormlite.core;
requires ormlite.jdbc;
...
But now I cannot compile the project anymore because both core and jdbc have the same package com.j256.ormlite.db.
[ERROR] module ormlite.core reads package com.j256.ormlite.db from both ormlite.core and ormlite.jdbc
I understand that this is as it should be, because split packages are not allowed. But how do I handle this, since this is not within my power? At least not in a clean way. I want to keep everything in maven and dont want to combine the packages as suggested in another post.
How can I solve this clean?
(I see that this is already an open issue in the orm-lite Github, but I do want to use it now)

Discrepancy with the same maven module having different versions of given dependency

It's kind of hard to explain my problem with words, so I took a pic, which shows exactly what my problem is:
As you can see, I have 3 relevant modules, a global, genui and web.
genui depends on global and web depends on genui.
Directly, web doesn't depend on global, but through genui it obviously does.
As you can see, if I take a look at the hibernate version of web->genui->global, it is 5.2.14, but if I look at it from genui->global, it's 5.3.0.
There is not, and there have never been any versions of either of these modules other than 1.0-SNAPSHOT.
I tried cleaning, deleting the files from .m2/repository, and even tried purging the local repo completely, nothing worked. I have no idea where maven gets the 5.2.14 number, I don't remember ever putting that in. The version is received from a property in parent module.
I figured out that the problem is caused by the pom.xml of web module, more specifically this part:
<dependencyManagement>
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
...
</dependencyManagement>
You probably need to exclude that repeated dependency from one of the spring ones... verify all your dependencies and look which are the ones that include hibernate. Check that you also have different versions for servlet-api.

Replace provided Maven dependency with local class

If I check my effective pom I will find the following entry:
<dependency>
<groupId>com.package.of.other.department</groupId>
<artifactId>someArtifact</artifactId>
<version>2.4.2</version>
<scope>provided</scope>
</dependency>
This comes from the parent pom that we have to use to let our software (bpmn processes) run on a company wide platform.
Now comes a hacky part. There will be a bigger change and we cannot use someArtifact anymore. Unfortunately that artifact gets called directly by all our processes (you design the process and configure the full qualified class name for an item) and can't just configure a different artifact, as that would most likely break a lot of the running processes.
The simple plan was to create a class with the same package name and with the same class name, remove every dependency to the original package and everything should work fine. During the tests I noticed that it doesn't use my new class but still the original one, most likely because it gets provided as dependency via the mandatory parent pom and for some reason prefers that over my local one.
Excluding a provided dependency from the parent pom doesn't seem to work that easily?! Any idea how I could solve my issue?
If the application is regular java, the class that will be load is the first class met in the classpath order.
If you use other runtime package dependency management, the strategy is different. As example you can adjust your import-package in OSGi to ensure the use a class contains in private-package.

Maven: Resolving Duplicate Dependencies

I'm developing an application that will be used internally at our company. In order for it to interop with our other internal systems I have to use some maven dependencies that we use internally, but this is causing some issues with using some external 3rd party dependencies that I also need.
So essentially my pom looks like this:
<dependencies>
<dependency>
internal-framework-artifact
</dependency>
<dependency>
necessary-third-party-artifact
</dependency>
</dependencies>
I've come to find that both of these dependencies have the apache's commons-collections as one of their own dependencies (among a large number of others, but we'll just keep it at one for this question's simplicity).
If I place exclusion rules on both of them for the commons-collections pom I can compile the project, but my resulting jar won't have access to either version of commons-collections and will just result in a java.lang.NoClassDefFoundError exception. Removing the exclusion rule on either of them just results in a mvn compiler error:
[WARNING] Rule 2: org.apache.maven.plugins.enforcer.BanDuplicateClasses failed with message:
Duplicate classes found:
I've been looking through various so q/a's and I can't really seem to find something that's 100% relevant to my situation. I'm really at a loss as to how to resolve this. Am I missing something really obvious?
I've never actually used the maven-shade-plugin for shading, but I think this is the exact use case it was designed for.
Create a new project that uses the maven-shade-plugin (see: http://maven.apache.org/plugins/maven-shade-plugin/) to produce an uber-jar version of internal-framework-artifact which contains that classes in internal-framework-artifact and all its dependencies. Configure the plugin so that it relocates all the classes that are also dependencies of necessary-third-party-artifact to some non-conflicting package names. This new project should produce a .jar with a different name, something like internal-framework-artifact-with-dependencies.
Now modify your original pom so that it is dependent on internal-framework-artifact-with-dependencies instead, and it should work.

Cannot resolve symbol 'Immutable'

I'm new to threading in java and now read the "java concurrency in practice". As you possibly understand I'm trying to do any examples but can't. when I'm trying to use #Immutable annotation IDE(Idea) underlines it red.
What is the possible reason of this?
The reason is that you do not have the correct jar in your classpath.
The maven artifact for this jar is:
<dependency>
<groupId>net.jcip</groupId>
<artifactId>jcip-annotations</artifactId>
<version>1.0</version>
<dependency>
If you do not have this jar in your classpath, you don't have the annotation.
Note however that this is superseded by JSR 305. There is also a Maven artifact for an implementation of that JSR:
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
<version>2.0.1</version>
</dependency>
(side note: excellent choice of a read! This is one must-have book for all Java devs out there)
Download the jar file providing the jcip annotations and add it to the module dependencies.
As far as working with that book's examples, so all those annotations, like #ThreadSafe, #Immutable/#Threadsafe, they all are just symbolic (though fge above is correct, you can use those jars as well, but from learning perspective, just ignore them)
So, simply ignore them. Anywhere, if you see #Immutable, it simply means that code written is IMMUTABLE, by the virtue of code implementation.
You don't need any jar at all. Just remove those annotations from your examples :)

Categories

Resources