Loading a class from single jar among several jars - java

I want to you use a class 'javax.xml.stream.XMLOutputFactory' in code.
The class (XMLOutputFactory) is available in more than one jars of library which got included as maven dependencies.
Problem : The class(XMLOutputFactory) is loading from the jar file while i am expecting to load from other jar.
Is there any solution to customize the loading of a class from the specific jar file.

Not on the java side (or maybe by implementing a new classloader but that is not a reasonable solution to your problem).
You should probably just exclude the dependencies (versions) you don't want in your pom file.

Since maven 2.0.9 the classpath is generated according dependencies declaration in pom.xml.
From maven site:
Note that if two dependency versions are at the same depth in the dependency tree, until Maven 2.0.8 it was not defined which one would win, but since Maven 2.0.9 it's the order in the declaration that counts: the first declaration wins.
So you can solve your problem if you take care of dependencies ordering in your pom.xml

Related

How to find java classes that needs a dependency in maven pom.xml file

I have a Maven based project, and I use IntelliJ. The pom.xml file probably contains dependencies that I don't need. How can I find which Java files (in particular the import statements) that need a specific dependency in the pom.xml file? Alternatively, how can I find which dependencies I don't need in the pom.xml?
I have tried to comment out a dependency from pom.xml, build the project and look what breaks. In at least one case, I saw no compile time problems, but there was a runtime problem. This method is also more effort than I want.
I have also tried to find information in the IntelliJ Project explorer, section "External Libraries". But the items listed there are not always present in the pom.xml file. Each versioned item there expands to a tree with a jar file on top, and I can ask IntelliJ about the usage of the contained items. I have found the usage of some packages contained in jar files, but the number of packages to investigate simply becomes too large.
Here is a dependency that I want to know if I need or not:
<!-- https://mvnrepository.com/artifact/com.googlecode.soundlibs/mp3spi -->
<dependency>
<groupId>com.googlecode.soundlibs</groupId>
<artifactId>mp3spi</artifactId>
<version>1.9.5.4</version>
</dependency>
This particular dependency results in three items in the External Libraries list (there are two sub dependencies apparently). Asking IntelliJ for usage of these libraries, I can't find any usage in my own files. But if I remove the dependency from the pom.xml file, I get runtime problems.
Maven offers you the dependency:analyze goal which gives you the artifacts that are declared in your pom but not used by any part of your source code. Beware, though, that there may be dependencies that are only used at runtime.

How to tell the project to download internal dependency?

I have a JAR. It is not a FAT JAR. It only contains my classes. But my JAR has a dependency upon azure-servicebus. I don't want to add azure-servicebus to my jar and make it a fat jar.
I just want that when the project adds my jar, it should download azure-servicebus automatically.
I am using Maven to create a jar (without dependencies).
How do I specify that? Is this possible?
edit:
I want the project that is adding my jar as a dependency should download azure-servicebus WITHOUT project having to add dependency for azure-servicebus or me packaging azure-servicebus within the jar file.
Assuming you already have a maven structue in your project, you would add the following line to your pom.xml:
<!-- https://mvnrepository.com/artifact/com.microsoft.azure/azure-servicebus -->
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-servicebus</artifactId>
<version>1.2.12</version>
</dependency>
If you don't have a maven structure, you'd need to generate one. This usually can be achieved within the IDE you're using.
If you want the resulting jar not having the service-bus, you can make the dependency some kind of compile only, which would be more or less a duplicate of this question: Is there a Maven "compiler-only" scope for dependency artifacts .
However, this would imply that your target runtime has to include the definition for the classes in some way (via -cp switch maybe).
From my POV: If you need a dependency to run your program, include it as long as the licence allows that.
If I understand you correctly, the structure you are talking about is:
some-project depends on your-jar which depends on azure-servicebus.
If some-project declares a Maven dependency on your-jar, then it gets azure-servicebus automatically as dependency because Maven does transitive dependency resolution. So when you build some-project, azure-servicebus will be on the class-path and if some-project is a WAR/EAR, than azure-servicebus will be part of that WAR/EAR.
I asked this question without knowing something very important.
When jars are put into artifactory, a corresponding .pom file also has to be placed alongside it (outside of the directory). This pom file is what tells the dependent project that the jar you are dependent upon, requires so and so dependencies itself.
This answer helped me understand:
https://stackoverflow.com/a/50002072/4828463
Thanks to everyone who tried.

Maven Adding dependency for specific java package

I have two version of the same jar file. (version 1 and 2). My problem is that i want classes in a specific package to use one version and classes in another package to use the other version.Both the packages are under the same maven project.
Tried to add both the jar files as dependencies in the POM, but the second entry overrides the first one and only one version is added as dependency.
Is there a way to achieve this in Maven.?
Think about DLL Hell. The only way you can get various versions of the same class to coexist in a single JVM is to load each using a different class loader, and you don't want to go that way.
Rewrite your code so all of it works with the newest version of the library, or rewrite it so it doesn't need whatever changes in the library require you to use v2, your choice.
Token ugly solution...
Split your project into two modules, where each module uses a different version of the dependency. To avoid the class-loader problems referenced in jwenting's excellent answer, use the Maven Shade Plugin to rename the dependency packages in one of the modules.
See Relocating Classes for an example of doing this.

Indirectly referenced from required .class files

I'm getting below error in STS:
The type org.springframework.core.env.EnvironmentCapable cannot be resolved. It is indirectly referenced from required .class files
This sounds like a transitive dependency issue. What this means is that your code relies on a jar or library to do something - evidently, you depend on Spring framework code. Well, all that Spring code also depends on libraries and jars.
Most likely, you need to add the corerctly versioned org.springframework.core jar to your classpath so that the EnvironmentCapable class can be found when your IDE attempts to build your project.
This might also be a jar collision issue as well, although that sounds less likely. When an application experiences jar collision (also known as "dll hell"), the compiler is finding multiple jars and classes with the same fully-qualified name. For example, let's say you added Spring to your classpath, along with the entire Tomcat server library. Well, those two jars may contain the same exact named classes, maybe the same version, maybe different versions. But either way, when the compiler looks for that EnvironmentCapable class, it finds two (in this contrived example) - one in the Spring jar and one in the Tomcat jar. Well, it doesn't know which one to choose, and so it throws a ClassDefNotFoundException, which would/could manifest itself as the error you experienced.
I faced same error while i work with spring security on spring-security-config.i jsut deleted that jar in maven repo and gave maven->update Project in eclipse.
it is resolved.Please try it once.
From command line, run "mvn clean install", you'll see project failed and you'll see artifacts in the logs that cause such a problem.
After that, remove artifacts from .m2/repository, then maven update from eclipse.
To avoid jar collision, make sure you declare your dependency versions under the properties tag in the aggregate pom.xml, and use the property name as a placeholder throughout the project. For example 4.2.5.RELEASE in the parent pom, and then in the child modules just use ${spring.version} instead of 4.2.5.RELEASE. This way you can avoid having two different versions of the same library on the classpath.
Also it is recommended to be consistent with the version of spring dependencies. Use the same version for spring-core, spring-web etc.
If you are using maven, then you can use the maven enforcer plugin to ensure dependency convergence, and avoid further issues with transitive dependencies.

Exclude certain dependencies from class path in a maven project

I have a maven project with some dependencies. Some of them have transitive dependencies which depend on, say, some jar A. I want to exclude this jar. Okay, I can add exclusions to every dependency which itself depends on A. But its a bit tedious. Is there any way to put this exclusion in one place in a maven project configuration?
Use a parent pom where you have <dependencyManagement/>. Then extend this parent in your POM files.
Alternatively, if it's one project that contains all these dependencies and they contain a transitive dependency with multiple versions on the dependency tree, define that dependency explicitly in your POM file and this will override the transitive versions.
See my explanations here for a similar question.
OKay, it looks like there is no way to do this.
According to documentation
Why exclusions are made on a per-dependency basis, rather than at the POM level
This is mainly done to be sure the dependency graph is predictable,
and to keep inheritance effects from excluding a dependency that
should not be excluded. If you get to the method of last resort and
have to put in an exclusion, you should be absolutely certain which of
your dependencies is bringing in that unwanted transitive dependency.

Categories

Resources