Maven Transitive Dependency causing NoClassDefFound error - maven

I am getting NoClassDefFoundError while trying to load a class which seems to be due to dependency version conflict.
Project A -> Project B -> Project C.
We have included version 2.0 for Project C within Project A.
whereas
Project B needs version 1.0 for Project C.
Right now when Project B code tries to load the class from Project C, it gets version 2.0.
Is there a way, I can explicitly define to refer to Project C (version 1.0 ) if project B tries to do so and in all other cases it should pick version 2.0
I mean the way we can exclude the transitive dependency, Is there a way to explicitly define inclusion ( only for the reference from the respective project and not the whole application code ).
Thanks.

I seriously doubt that. If I understand the question correctly, your build would result in loading the jar of project C in two different versions simultaneously into the JVM (one for Project B and one for Project A). As they probably share the same packages and class names, there is no way for the JVM to distinguish them.
If project C is your own project and the change from version 1.0 to 2.0 breaks something, I would think about using a new package name, like org.example.c2 instead of org.example.c (like e.g. in the Apache commons-lang project).

Related

Do dependency versions affect substitution of included builds in a Gradle composite build?

Context
I have one project (A) that depends on another (B), both using the Gradle build system. Project A usually declares a dependency on a specific version of B. When modifying project B, it's convenient to immediately see the effects on project A. Using includeBuild in settings.gradle or --include-build on the command line, the build of project A is reconfigured to include the local development version of project B instead of a published artifact (a "composite build"). However, this local copy of project B declares a development version number, not the stable release version requested by project A. To ensure that the included build of B satisfies the declared dependency in A, I have been changing A to request a version range like org.example:B:[v6, ) instead of org.example:B:v6.0. However, I see that the build succeeds even when A specifies nonsensical version numbers that do not correspond to B.
Question
How do versions affect this dependency substitution process?
Research
The documentation I have read (linked below) shows how to include a build, but does not mention version numbers.
https://docs.gradle.org/current/samples/sample_composite_builds_basics.html
https://docs.gradle.org/current/userguide/composite_builds.html#defining_composite_builds
Some hints may be present on this page covering "brute force" modifications of dependency resolution:
In composite builds, the rule that you have to match the exact
requested dependency attributes is not applied: when using composites,
Gradle will automatically match the requested attributes. In other
words, it is implicit that if you include another build, you are
substituting all variants of the substituted module with an equivalent
variant in the included build.
Although this deals with "variants" and their "attributes", which according to the dependency terminology documentation seem to be distinct from module versioning, the statement seems related. Can something similar be said about dependency module versions?

Can we generate a BOM that exports generated artifacts as dependencies out of a Maven project?

I have the following situation: I inherited a legacy system, built as a multi-module Maven project.
parent
module1
module 1.1 -> generates artifact 1.1
module 2.2 -> generates artifact 1.2
module2
module 2.1
module 2.1.1 -> generates artifact 2.1.1
module 2.1.2 -> generates artifact 2.1.2
module 2.2 -> generates artifact 2.2
module3 -> generates artifact3
This is the current situation, and for a long list of reasons, it cannot be altered.
Furthermore, these artifacts (their subsets or their totality) get consumed as dependencies by other projects. These projects are built by other teams using processes outside of my control, and it becomes a hassle to get everyone on board to consume the correct versions.
I'd love to be able to generate a BOM that lists each generated artifact as a dependency in a dependency management section, with the correct versions, then publish that one BOM for everyone else to consume.
Kinda like the master/parent bom published by the Spring Framework.
Then, it'd be voila! I could try to create the BOM manually, but I'd rather not do that.
The legacy project I inherited is not the only one with these challenges. If I could find an automated way to do this, that'd be a great win for me and my co-workers.
I don't find any references on how to generate one such bom.
I only see documentation on how to use one, or how to create one manually for a project's dependencies.
I don't see any documentation on how to generate one that lists/exports the artifacts created by the project (for others to consume.)
Thanks.
PS. This project is not the only one. There are other projects being built and consume like that in a nightmarish 11th-dimensional quantum-entangled hyper-spaghetti ball of dependency doom (wink, wink.)

How to resolve depedency between different versions

I was exploring maven, currently using Ant. The application which we use here have different modules.
Now if I add dependencies to those how I can solve version conflict. Example module A has the dependecy of version1. while module B has the dependency of version2 now If someone need to work with both the module together than it will automatically resolve to version2 that is higher version.
Is there any internal behavior of maven or any command that I can use to resolve version conflicts?
Maven "solves" this problem by using the nearest declaration for transitives dependencies.
e.g.
A -> X -> externalLib 2.0
B -> externalLib 1.0
C -> A,B will result in using externalLib 1.0 since the declaration (over B) of 1.0 is nearer to C that over A and X
If they have the same distance the position within the POM file decides.
This is typically not the kind of "solution" you want. Since they might be incompatible it is better to choose a version manualle explicitely and declare this version in the pom of C
C -> externalLib 2.1
Note, if there is no version that is compatible to both X and B, there is no solution and Java does not support several versions of the same lib in one classloader. In this case you thould think of using OSGi or similar.
this link provides solution to your problem
http://maven.apache.org/guides/introduction/introduction-to-optional-and-excludes-dependencies.html

How do the dependencies of a maven project become available to it at runtime?

I have my POJOs and DAOs in one maven project (Project A)
And I have created a Service in another maven project collecting the DAOs I need (in Project B)
And I created a third maven Project with a swing gui main class(Project C)
Project C depends on B and B depends on A.
When I declare my service(Project B) to use the functions to fetch data to the gui (Project C) I get a Java Null Pointer Exception on the Resource use of my service.
Cant the project communicate just trough dependencies or do I need some deserialization etc.?
LOGIC
POJO(implements Serializable) -> DAO -> Service -> GUI
So, it seems that you are executing the code in Project C. It would help to know what the types of these projects are . . . but let's just assume they are jars. By default, a jar is NOT built to include all of it's dependencies inside of itself. This is because Maven expects you to use jars like most people in the java community do, i.e. they are installed into runtimes along with all of the other jars needed. If each jar had it's fully dependency tree included inside of itself, that would be a mess. So, it seems that you are expecting the Maven build to pull all of your dependency chain into your final artifact for Project C, and it's not happening.
There are several ways to get your dependencies into your final artifact. Assuming your swing project is a jar, you could do this with the assembly plugin's "jar-with-dependencies" assembly type. It produces a jar with all of it's dependencies included.
http://maven.apache.org/plugins/maven-assembly-plugin/descriptor-refs.html#jar-with-dependencies
This was what i needed to fetch data from my maven project (Project A) http://www.java2s.com/Code/Java/Spring/LoadconfigwithFileSystemXmlApplicationContext.htm

How to create a maven assembly with transitive dependencies for different deployment scenarios?

I'm having a problem reconciling building a project for use within an application server and for use as a stand-alone application.
To give an overall simplified context, say I have three Projects A, B, C.
Project A depends on Project B which depends on Project C.
Project C has a dependency X which is marked as provided since it was expected that it would be available as a JEE library within say an application server. i.e. jms.jar.
So if I perform an assembly build of Project A, I get all the transitive dependencies save for those marked as provided as expected.
Now I have a new deployment scenario where Project A needs to be used in a standalone environment i.e. outside an application server.
So now I need the jms jar to be a compile dependency. Does this mean that I should explicitly add a compile dependency for X in Project A? Doesn't this violate the Law of Demeter, i.e. don't talk to strangers, in the sense Project A shouldn't explicitly know about Project C but only about Project B?
This is a simple example but in reality I have multiple dependencies which have been marked as provided but are now need to be compile or runtime dependencies so they end up in the artifact produced by the maven assembly plugin.
Is this a fundamental problem with Maven or am I not using the tools correctly?
Thanks in advance for any guidance.
If you need your build to have variations in it for different scenarios, you need to use profiles and keep certain things (such as some of the dependencies) in the various profiles.
http://maven.apache.org/pom.html#Profiles
Different dependencies for different build profiles in maven
answers a similar question - but you can swap in the "release" and "debug" for "Project A" and "Project C"
Provided dependencies are a difficult subject. First of all: Provided dependencies are not transitive in the following sense: If your project C has a provided dependency on X, then A will not get the dependency. It is silently ignored. This fits with the following meaning of "provided" which I propose:
Only the artifacts that are actually deployed should mark dependencies as "provided". Libraries or other jars that are not individually deployed to a specific server should not have provided dependencies. Instead, they should declare their dependencies as compile dependencies. In your example: Project C should have a compile dependency on X. If project A knows that X is provided, it sets X to provided in "dependencyManagement". As project A should know the environment in which it runs it should decide what is provided and what is not. And "dependenyManagement" is the right place to declare this.
If your project A should be able to run within and without a given server, you probably need to make a lot of adjustments, even change the type from ear to jar. So you either use build profiles for this, which then have different dependencyManagement entries, or you split A into two projects which depend on some other project that contains the common elements.
If some given project C already has a provided dependency on X and you cannot change that, this is effectively the same as a missing dependency in C. This has to be repaired at some point, and this could be project A itself.

Resources