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.
Related
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.
I have been battling dependencies on a Java Maven multi-module project for a couple of days.
With too little oversight developers managed to create a situation where modules each can be compiled on their own but not as a single whole together. This results in all kinds of errors. Classes that cannot be found, casting errors etc etc. The cause of these problems seems impossible to determine.
My suspicion is that Maven puts conflicting dependencies on the class path. I think we made a mess of the Maven dependencies but regardless I don't understand how Maven can be such a poor performing framework for multi-module projects.
Now I can understand that Maven tries to do very smart useful things when compiling multiple modules as a whole but shouldn't there be an option in Maven to just configure a module to be isolated from other modules? Is there such an option? To avoid this dependency hell?
Or is the Maven best practice to create other scripts, bash scripts for example to be able to compile multiple modules in isolation, with one command?
But that is also poort workaround some tools for example SonarQube require ability to run Maven on the whole code base in order to create a single project in SonarQube.
This results in all kinds of errors. Classes that cannot be found, casting errors etc etc. The cause of these problems seems impossible to determine.
Could you post the error messages? it would make analyzing your issues easier. This may be caused by dependency conflicts, but it is hard to say without more information.
Now I can understand that Maven tries to do very smart useful things when compiling multiple modules as a whole but shouldn't there be an option in Maven to just configure a module to be isolated from other modules? Is there such an option? To avoid this dependency hell?
I do not get this. If two modules do not depend on each other, their builds will be independent. If one module depends on another module and its build fails because of version conflicts, this build will fail regardless of whether it is built together with the other modules or in isolation.
Or is the Maven best practice to create other scripts, bash scripts for example to be able to compile multiple modules in isolation, with one command?
Maven follows the philosophy "convention over configuration", meaning the more you follow the convention, the less configuration you will have and the less maintenance work. Creating all kinds of scripts goes against this philosophy and is not Maven's best practice.
To manage dependency conflicts in a multi module project, you would typically have a parent module with a pom.xml that looks like
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>...</groupId>
<artifactId>...</artifactId>
<version>...</version>
<packaging>pom</packaging>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>6.0</version>
<scope>provided</scope>
</dependency>
...
</dependencies>
</dependencyManagement>
<modules>
...
</modules>
</project>
In the dependendencyManagement element you define the version of libraries used. This way you force each module to use the same version of libraries.
For Maven, I often recommend the Java EE NetBeans IDE, because among other things it has a good visualisation tool for dependencies, which is useful in detecting and removing version conflicts. (I am not aware of a similar tool in Eclipse or IntelliJ). If you open a Maven project in NetBeans, click on the pom.xml (in the Projects window) and then select Graph > Show Graph.
I use this tool for 2 things:
remove the transitive dependencies in Maven, otherwise you have to manage more dependencies than required. To remove transitive dependencies, right click in the graph and select the Hierarchical layout. Every dependency that is not on the first line is a transitive dependency and can be removed from the pom.xml.
identifying conflicts between transitive dependencies. (Conflicts are coloured red in the graph.) I resolve these conflicts by explicitly setting the version for the dependencies in the dependencyManagement element in the root pom.xml
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.
I have a maven-java project (say Project A) with a parent defining modules in its pom.
I also have an external project (say Project B) that requires dependencies of two of the modules from Project A. For now, i have defined the dependency to pull each module individually.
When i replace these two with a dependency on the parent pom, it errors out on build. Is there some modification i need to make to my parent pom of Project A to make this work?
Can this be done in the first place?
Can this be done in the first place?
Declaring a dependency on an aggregating POM won't get the modules transitively. This is not going to work. It is possible to create a POM to group dependencies though.
For example, EHCache uses this technique. As mentioned in their documentation:
Maven Snippet
To include Ehcache in your project
use:
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.0.1</version>
<type>pom</type>
</dependency>
The net.sf.ehcache:ehcache artifact is precisely used to group dependencies (and is distinct from net.sf.ehcache:ehcache-parent).
References
The Maven Guide
3.6.1. Grouping Dependencies
Say I have two Maven dependencies defined in a project like below.
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.3.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mycompany.library</groupId>
<artifactId>mylibrary</artifactId>
<version>1.0.1</version>
<scope>compile</scope>
</dependency>
Then, within mylibrary, I also have a dependency defined as below.
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.3.1</version>
<scope>compile</scope>
</dependency>
When I package my project, I don't see xstream packaged within it. I think the project's xstream dependency scope, 'test' is overriding the mylibrary's xstream dependency scope, 'compile'.
In this kind of situation, what's the best way to include the xstream for the whole project so the submodule can have access to it when packaged within the project?
I've read Apache Maven website's explanation on Transitive dependencies, but I'm struggling to understand what it means, and also to find out the best practice in this situation.
This feels really odd to me, and if it's "feature", I think it is a really dangerous one.
Anyway, it's not a Maven bug and it's in the maven documentation here.
Regarding best practices on this issue, I haven't heard of any, but the safest way to proceed ought to be to entirely remove xstream from your pom, relying on the transitive dependency. Doing this will result in a build failure if the dependency to mylibrary is removed. This will act as a notification to you that you need to fix something. You won't silently loose required dependencies, and you won't silently have dependencies you no longer need.
On a side note, mvn dependency:analyze can be used to check for dependencies that are included but not used.
As mattb's answer says, declaring the dependency as test scope overrides the transitive compile-scoped dependency declaration, and as a result the dependency is not included in your packaged war.
If you only need the dependency in your tests because 'mylibrary' needs it to execute, you shouldn't declare the dependency at all in your project's pom. Let the transitive dependency resolution process handle it.
If your project does use the xstream jar directly, you can still rely on the transitive dependency, as you will need a compatible version for your project and 'mylibrary' to both run against the xstream jar. You should have unit tests that exercise the functionality, and if mylibrary changes version of xstream to an incompatible version, your builds should fail, and you can address the issue at that point.
In general I'd say you should try to avoid declaring dependency versions directly in multi-module projects. I declare the versions in a dependencyManagement section of a parent POM so that the child need only declare the groupId/artifactId. Alternatively, from Maven 2.0.9 onwards there is an additional dependency scope of import:
This scope is only used on a dependency of type pom in the section. It indicates that the specified POM should be replaced with the dependencies in that POM's section. Since they are replaced, dependencies with a scope of import do not actually participate in limiting the transitivity of a dependency.
So using import scope you can define your common dependency versions in a single POM, import the dependencies of that POM into your dependencyManagement section, and just declare the groupId/artifactId of the dependency in your other POMs.
By declaring your own dependency on xstream, and setting the scope to test, you are overriding the dependencies declared by mylibrary.
This is actually a Maven feature - it allows you to do things such as depend on a later version of a transitive dependency within your own project, and not end up packaging two different versions of the same artifact. For example, you might depend on version 1.2.15 of log4j, but because you also use libraryX which depends on log4j-1.2.14 - you wouldn't want both log4j-1.2.15 and log4j-1.2.14 to be packaged with your project.
If you actually want xstream to be packaged within your project, you should not be declaring the scope as test. In fact if you remove your listed dependency on xstream, things will work out as you like, since mylibrary has a compile dependency on it..
If you want it packaged, why are you declaring scope? If it is required at compile and execution time, shouldn't you leave the scope blank? If you did that, then you would only need
<dependency>
<groupId>mycompany.modules</groupId>
<artifactId>submodule</artifactId>
<version>1.0.1</version>
</dependency>
in your pom. Unless there is a reason to descope it during compile but not during packaging?