I added a maven project as dependency in another maven project - java

I added a maven project A as dependency in another maven project B and then access the jar created by B in another project through reflection, but its throwing a NoClassDefFound error for classes in maven project A
My question is, how do I make the classes in project A visible on project B's classpath? I tried adding a MANIFEST.MF but that seems to only work for jars and class files. All help appreciated.

Nature of a maven dependency is specified by a four-tuple (a collection of four things): GroupID, ArtifactID, version, and the often forgotten scope. The first three are collectively known as GAV of a dependency. The scope determines how the dependency is to be utilized at runtime.
In your case, what seems to be happening is that the following:
Project A is compiled and installed in a local repo (e.g. using a mvn install command).
In Project B's pom.xml, you specify project A's GAV as a proper <dependecy> declaration and compilation and packaging seems to go through.
But since the project B's final JAR does not have project A's classes, running project B fails because A's classes are not found.
Basically, you need to tell Maven the scope of the dependency. In your case, since project A's classes are not available at a predefined runtime (e.g. Tomcat, or GlassFish web container) you need to be make sure that you bundle them with the JAR file of project B.
This is where you need a plugin attaching to a phase of build life cycle.
See maven-jar-plugin or maven-shade-plugin for details on how to make project A's classes a part of project B's final JAR file.
This assumes that you are running the classes in B as: java -jar projectB-full.jar.

Add commons-logging dependency to your project A (the one you are using as a dependency):
<!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
Next, go to the "maven" tab, reimport dependencies, next build project A running mvn clean install. Then go to your project B, verify you have project A as a dependency (correct groupId, artifactId, and version) and reimport the dependencies.
Your project B should now recognize your project A dependency.

Related

what does happen with maven dependencies

suppose I have a project say A which is dependent on B. so when I build project A. does maven generates the artifact of A by bundling with project B artifact?
and suppose if project B is dependent on C. then when I build project A, will it by default takes the transitive dependency c to generate the artifact? and even if it takes, what will happen if I add C as a dependency in project A pom.xml? will maven takes the C artifact for two times to build A and generates a bigger artifact file?
what will happen if I add C as a dependency in project A pom.xml?
If C's dependency has already been resolved, maven will simply ignore it if it is declared elsewhere.
will maven takes the C artifact for two times to build A and generates a
bigger artifact file?
No.
Please check https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Transitive_Dependencies for more details.
Transitivity brings a very serious problem when different versions of the same artefacts are included by different dependencies. It may cause version mismatch issue in runtime. In this case, dependency:tree command is very useful in dealing with conflicts of JARs.
$ mvn dependency:tree
Check https://howtodoinjava.com/maven/maven-dependency-management/#dependency-tree for more details.
this question is a little bit broad, things can change a little with you start to talk about Maven multi-module projects (so there is a parent-child relationship between modules). I will assume that multi-module setups are off-topic for this question.
Also: IDEs have tight integration with Maven and might add additional automatic processes on top of it. I assume this is plain Maven as it would work from a shell.
finally: there is a big difference from working with dependencies you pull in from the internet and projects you are building yourself with Maven. I am going to limit this answer to only building your own projects when it comes to dependency management. Otherwise I'd be writing the Maven manual here.
suppose I have a project say A which is dependent on B. so when I
build project A. does maven generates the artifact of A by bundling
with project B artifact?
Maven will include whatever you put in the dependencies listing; if it cannot it will fail the build. If project B is your own project, it will not automatically build B for you when you are building project A, it will only try to include whatever jar is already in your local maven repository. If there is no jar in your local repository, it will try to download it from all the Maven repositories that are known within the project. This will fail if Project B is just a project living on your harddrive, the only way then to make the jar of Project B available for usage in Project A is to actually build and install Project B first so a copy of the jar is put in your local maven repository.
Similarly if project B changes but you do not change its Maven version number, it is your own responsibility to rebuild and install it so the existing jar in your local maven repository gets overwritten.
It is possible that the dependency jar of B is pushed to a remote repository; it could be that your company is hosting or licensing a Nexus or an Artifactory for example and development builds are pushed to a snapshot repository so it can be used by several developers on different machines without them having to checkout the project and build it on their own machine. Then it depends on how Maven is configured if it will eagerly download updated versions of the jar when building project A. If you are working with a remote repository and you suspect that during the build an older version of a dependent jar is being used, this existing question's answers detail a few ways to force dependency jars to be updated when they were already downloaded before. But you should hardly ever need to use that.
and suppose if project B is dependent on C. then when I build project
A, will it by default takes the transitive dependency c to generate
the artifact?
Yes it will walk the entire dependency tree and include all transitive dependencies.
and even if it takes, what will happen if I add C as a
dependency in project A pom.xml? will maven takes the C artifact for two times to build A and generates a bigger artifact file?
Well first of all: dependencies are not included in the jar of project A by default so the size of the jar does not depend on the number of dependencies the project has. You would have to specifically use a plugin that has this functionality, often called "one jarring", "creating a fat jar" or creating an "uber jar". The Maven Shade plugin is a common way to do this.
Regardless, Maven does not allow multiple copies of the same dependency groupId+artifactId pair to exist on the classpath and will filter out duplicate copies when it finds them. This also happens when you add the same artifact multiple times within the same pom, Maven will call you out on it and include only one copy.
So no, in the end there will be only one copy of C.jar. Even if the pom of A refers to C version 1.0 and the pom of B refers to C version 1.1.

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 way to include a runtime dependency when packaging

I have two Maven projects, A and B, where A depends on B at compile time, but at runtime B needs some classes of A.
What I did is:
A's pom.xml
<dependency>
<groupId>B</groupId>
<artifactId>B</artifactId>
<version>${B.version}</version>
</dependency>
B's pom.xml
<dependency>
<groupId>A</groupId>
<artifactId>A</artifactId>
<version>${A.version}</version>
<scope>runtime</scope>
</dependency>
When letting Jenkins compile the projects it fails to compile each other as a downstream project because it finds the circular dependency and avoid the infinite build loop.
So, what I thought is a way to add the A's runtime dependency only when packaging B (when Jenkins executes mvn package) so that Jenkins does not find the circular dependencies in the pom.xml files and configures the downstream compilation.
Is there any way to accomplish this with an existing Maven plugin or other way?
Thank you
I wrote this Maven plugin for the same reason.
It adds any listed JAR artifact to the WAR file where this plugin is used. JAR dependencies are resolved and added to the WAR file if not artifact with the same version is found.
The important thing is to define dependencies only inside the <dependency> POM section because that's the only configuration used by the Maven reactor.
If you fiddle with custom plugins to introduce your own dependency management ideas you will most likely break the reactor. Even if your custom approach works with regular mvn clean install it will usually explode when -T4 or similar option is used to enable multi threaded builds. There is simply no way to explicitly define the module build order in POM as it's governed by the reactor.
The usual way of sharing code between modules is to create a new module C which is depended on by both A and B.

Add bundled maven project as external jar

I have a maven project that depends on another maven project which is not available on a public repo. Let's call them projects A and B, and A depends on B.
I'm currently pulling in B in project A by declaring it as an external dependency which I've placed inside an in project repo. (I call mvn bundle:bundle in project B and just copy the generated jar over to project A) The problem is, by doing this maven can't infer which dependencies B relies on since it's a bundled jar.
Let's suppose both projects A and B rely on another maven project C which is available on the remote maven repository. Project A uses project C, version 0.2 and project B uses project C, version 0.1. However, since project B is being loaded in project A as an external bundled jar, maven doesn't know this. During run time, project A tries to call a method which exists in C 0.2 but not in C 0.1. However maven built the project by importing project B first then C as the remote dependency, so C 0.2 is not in the bundled project A jar, and we get a runtime methodNotFound error.
Any idea how I can deal with this? Is it possible to just include a pom.xml file with the bundled project B jar somehow so maven knows that B relies on C as a dependency and can sort the issue out itself?
The way I'm currently working around this is just by manually setting the build order outside of maven and not using it at all for compilation.
EDIT: OK I got it to work by just including a (artifactId)-(version).pom file in the same directory as the jar for maven to get a dependency list
If you would use maven as per tutorials (e.g. here) it just works. Why are you doing bundle? Why do you need copy something? Just declare B as dependency in A's pom.xml and do mvn install for B, then A will use it from your local maven repo.
Also, if you just add both modules into single project (I'm using IDEA), IDE recognises the dependency.

In Maven, do modules get effected by the repository's updatePolicy?

This is just like this other question I asked, but instead of dependencies, this is about modules. Let me give a scenario. You've got a multi-module project and a continuous integration server that deploys the project. This deploys to a repository that your local settings.xml has an updatePolicy of always. Now imagine you run mvn compile right after the CI deploys the project.
Will you end up compiling against the remote server's modules, or your local modules?
In other words, does the updatePolicy of a repository have any effect on the module tags?
modules tag is an aggregation. It is not treated the same as dependencies. Notice that the value that you specify in dependency and module is different. When you declare a dependency, you specify maven coordinates. Whilst for module, you specify relative directories.
Will you end up compiling against the remote server's modules, or your local modules?
You will always end up compiling against your local module if you run the mvn compile in the aggregator module (NOT in the child module!) and the child module dependency is a sibling dependency. When you mvn compile in an aggregator module, the dependency lookup when it is compiling the child module will be special. It will look from the sibling modules target folder ONLY. I can't find documentation on this, but you can try it out.
Imagine that you have these aggregator pom
...
<modules>
<module>child-a</module>
<module>child-b</module>
</modules>
....
child-b pom is declaring a dependency against child-a. (Make sure you have a real output classes)
Next, when you mvn compile the aggregator pom, child-b will be able to compile even if you have NOT mvn install child-a before. That means, child-a is not even in your local repository. This is possible because maven will look into child-a's target folder for the classes. To confirm this, you can try to run mvn compile clean (yes, clean after compile).
Again, do note that this behavior only applies when you run it from the aggregator pom. If your current working directory is child-b (which is dependent on child-a), it will respect the updatePolicy when it tries to look for child-a.

Categories

Resources