Maven runtime dependency - java

I have 2 stub jars - say B.jar,C.jar which have XyZ.class in common.The dependency in pom is below:
<dependency>
<groupId>pack.y.b</groupId>
<artifactId>B</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>pack.y.b</groupId>
<artifactId>C</artifactId>
<version>1.0</version>
</dependency>
It is known that dependencies are loaded from pom.xml in the order it is mentioned as in Maven: Multiple class with the same path implemented in different jar that is indeed how it behaves i.e in local, I get XyZ.class loaded from B.jar right and if B is not available, it is loaded from C.
In contrary, during runtime after deployment, the class is extracted from C instead of B and I ain't sure why it happens and how to rectify. Please clarify and favour.

Related

Dependency of Type "POM"

I am trying to get an ESB system running using ServiceMix and ActiveMQ. But even before I get that far, I had a question about dependency types of POM. I got the maven dependency as:
<!-- https://mvnrepository.com/artifact/org.apache.servicemix/servicemix -->
<dependency>
<groupId>org.apache.servicemix</groupId>
<artifactId>servicemix</artifactId>
<version>7.0.1</version>
<type>pom</type>
</dependency>
Now when I run "clean install" on the the project in which I included this dependency, I don't see any of the activeMQ jars being copied in the classpath or available for compilation (I have copy-dependency written, so I can see what jar files are included). In this case, do I still have to explicitly mention the activeMQ dependency in my pom file? Like:
<!-- https://mvnrepository.com/artifact/org.apache.activemq/activemq-core -->
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-core</artifactId>
</dependency>
Any guidance would be appreciated. This ServiceMix is frustrating with the lack of documentation.
If you put a dependency of type pom into your <dependencies>, Maven will use the content of the POM as transitive dependencies. So everything in that POM will become a part of the classpath unless it has something like test scope or its version is overridden by some other part of the POM.
Putting a POM into the <dependencyManagement> is a different thing. Note that scope import is only for <dependencyManagement>.

Why are SLF4J Logger and LoggerFactory imports missing from maven project? [duplicate]

What is the difference between dependencyManagement and dependencies?
I have seen the docs at Apache Maven web site.
It seems that a dependency defined under the dependencyManagement can be used in its child modules without specifying the version.
For example:
A parent project (Pro-par) defines a dependency under the dependencyManagement:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8</version>
</dependency>
</dependencies>
</dependencyManagement>
Then in the child of Pro-par, I can use the junit:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>
However, I wonder if it is necessary to define junit in the parent pom? Why not define it directly in the needed module?
I'm fashionably late to this question, but I think it's worth a clearer response than the accepted one (which is correct, but doesn't emphasize the actual important part, which you need to deduce yourself).
In the parent POM, the main difference between the <dependencies> and <dependencyManagement> is this:
Artifacts specified in the <dependencies> section will ALWAYS be included as a dependency of the child module(s).
Artifacts specified in the <dependencyManagement> section, will only be included in the child module if they were also specified in the <dependencies> section of the child module itself. Why is it good you ask? Because you specify the version and/or scope in the parent, and you can leave them out when specifying the dependencies in the child POM. This can help you use unified versions for dependencies for child modules, without specifying the version in each child module.
Dependency Management allows to consolidate and centralize the management of dependency versions without adding dependencies which are inherited by all children. This is especially useful when you have a set of projects (i.e. more than one) that inherits a common parent.
Another extremely important use case of dependencyManagement is the control of versions of artifacts used in transitive dependencies. This is hard to explain without an example. Luckily, this is illustrated in the documentation.
The documentation on the Maven site is horrible. What dependencyManagement does is simply move your dependency definitions (version, exclusions, etc) up to the parent pom, then in the child poms you just have to put the groupId and artifactId. That's it (except for parent pom chaining and the like, but that's not really complicated either - dependencyManagement wins out over dependencies at the parent level - but if have a question about that or imports, the Maven documentation is a little better).
After reading all of the 'a', 'b', 'c' garbage on the Maven site and getting confused, I re-wrote their example. So if you had 2 projects (proj1 and proj2) which share a common dependency (betaShared) you could move that dependency up to the parent pom. While you are at it, you can also move up any other dependencies (alpha and charlie) but only if it makes sense for your project. So for the situation outlined in the prior sentences, here is the solution with dependencyManagement in the parent pom:
<!-- ParentProj pom -->
<project>
<dependencyManagement>
<dependencies>
<dependency> <!-- not much benefit defining alpha here, as we only use in 1 child, so optional -->
<groupId>alpha</groupId>
<artifactId>alpha</artifactId>
<version>1.0</version>
<exclusions>
<exclusion>
<groupId>zebra</groupId>
<artifactId>zebra</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>charlie</groupId> <!-- not much benefit defining charlie here, so optional -->
<artifactId>charlie</artifactId>
<version>1.0</version>
<type>war</type>
<scope>runtime</scope>
</dependency>
<dependency> <!-- defining betaShared here makes a lot of sense -->
<groupId>betaShared</groupId>
<artifactId>betaShared</artifactId>
<version>1.0</version>
<type>bar</type>
<scope>runtime</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
<!-- Child Proj1 pom -->
<project>
<dependencies>
<dependency>
<groupId>alpha</groupId>
<artifactId>alpha</artifactId> <!-- jar type IS DEFAULT, so no need to specify in child projects -->
</dependency>
<dependency>
<groupId>betaShared</groupId>
<artifactId>betaShared</artifactId>
<type>bar</type> <!-- This is not a jar dependency, so we must specify type. -->
</dependency>
</dependencies>
</project>
<!-- Child Proj2 -->
<project>
<dependencies>
<dependency>
<groupId>charlie</groupId>
<artifactId>charlie</artifactId>
<type>war</type> <!-- This is not a jar dependency, so we must specify type. -->
</dependency>
<dependency>
<groupId>betaShared</groupId>
<artifactId>betaShared</artifactId>
<type>bar</type> <!-- This is not a jar dependency, so we must specify type. -->
</dependency>
</dependencies>
</project>
There's still one thing that is not highlighted enough, in my opinion, and that is unwanted inheritance.
Here's an incremental example:
I declare in my parent pom:
<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
</dependency>
</dependencies>
boom! I have it in my Child A, Child B and Child C modules:
Implicilty inherited by child poms
A single place to manage
No need to redeclare anything in child poms
I can still redelcare and override to version 18.0 in a Child B if I want to.
But what if I end up not needing guava in Child C, and neither in the future Child D and Child E modules?
They will still inherit it and this is undesired!
This is just like Java God Object code smell, where you inherit some useful bits from a class, and a tonn of unwanted stuff as well.
This is where <dependencyManagement> comes into play. When you add this to your parent pom, all of your child modules STOP seeing it. And thus you are forced to go into each individual module that DOES need it and declare it again (Child A and Child B, without the version though).
And, obviously, you don't do it for Child C, and thus your module remains lean.
It's like you said; dependencyManagement is used to pull all the dependency information into a common POM file, simplifying the references in the child POM file.
It becomes useful when you have multiple attributes that you don't want to retype in under multiple children projects.
Finally, dependencyManagement can be used to define a standard version of an artifact to use across multiple projects.
Sorry I am very late to the party.
Let me try to explain the difference using mvn dependency:tree command
Consider the below example
Parent POM - My Project
<modules>
<module>app</module>
<module>data</module>
</modules>
<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
</dependencies>
</dependencyManagement>
Child POM - data module
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
</dependencies>
Child POM - app module (has no extra dependency, so leaving dependencies empty)
<dependencies>
</dependencies>
On running mvn dependency:tree command, we get following result
Scanning for projects...
------------------------------------------------------------------------
Reactor Build Order:
MyProject
app
data
------------------------------------------------------------------------
Building MyProject 1.0-SNAPSHOT
------------------------------------------------------------------------
--- maven-dependency-plugin:2.8:tree (default-cli) # MyProject ---
com.iamvickyav:MyProject:pom:1.0-SNAPSHOT
\- com.google.guava:guava:jar:19.0:compile
------------------------------------------------------------------------
Building app 1.0-SNAPSHOT
------------------------------------------------------------------------
--- maven-dependency-plugin:2.8:tree (default-cli) # app ---
com.iamvickyav:app:jar:1.0-SNAPSHOT
\- com.google.guava:guava:jar:19.0:compile
------------------------------------------------------------------------
Building data 1.0-SNAPSHOT
------------------------------------------------------------------------
--- maven-dependency-plugin:2.8:tree (default-cli) # data ---
com.iamvickyav:data:jar:1.0-SNAPSHOT
+- org.apache.commons:commons-lang3:jar:3.9:compile
\- com.google.guava:guava:jar:19.0:compile
Google guava is listed as dependency in every module (including parent), whereas the apache commons is listed as dependency only in data module (not even in parent module)
There are a few answers outlining differences between <depedencies> and <dependencyManagement> tags with maven.
However, few points elaborated below in a concise way:
<dependencyManagement> allows to consolidate all dependencies (used at child pom level) used across different modules -- clarity, central dependency version management
<dependencyManagement> allows to easily upgrade/downgrade dependencies based on need, in other scenario this needs to be exercised at every child pom level -- consistency
dependencies provided in <dependencies> tag is always imported, while dependencies provided at <dependencyManagement> in parent pom will be imported only if child pom has respective entry in its <dependencies> tag.
If the dependency was defined in the top-level pom's dependencyManagement element, the child project did not have to explicitly list the version of the dependency. if the child project did define a version, it would override the version listed in the top-level
POM’s dependencyManagement section. That is, the dependencyManagement version is only
used when the child does not declare a version directly.
Just in my own words, your parent-project helps you provide 2 kind of dependencies:
implicit dependencies : all the dependencies defined in the <dependencies> section in your parent-project are inherited by all the child-projects
explicit dependencies : allows you to select, the dependencies to apply in your child-projects. Thus, you use the <dependencyManagement> section, to declare all the dependencies you are going to use in your different child-projects. The most important thing is that, in this section, you define a <version> so that you don't have to declare it again in your child-project.
The <dependencyManagement> in my point of view (correct me if I am wrong) is just useful by helping you centralize the version of your dependencies. It is like a kind of helper feature.
As a best practice, your <dependencyManagement> has to be in a parent project, that other projects will inherit. A typical example is the way you create your Spring project by declaring the Spring parent project.
The difference between the two is best brought in what seems a necessary and sufficient definition of the dependencyManagement element available in Maven website docs:
dependencyManagement
"Default dependency information for projects that inherit from this one. The dependencies in this section are not immediately resolved. Instead, when a POM derived from this one declares a dependency described by a matching groupId and artifactId, the version and other values from this section are used for that dependency if they were not already specified."
[ https://maven.apache.org/ref/3.6.1/maven-model/maven.html ]
It should be read along with some more information available on a different page:
“..the minimal set of information for matching a dependency reference against a dependencyManagement section is actually {groupId, artifactId, type, classifier}. In many cases, these dependencies will refer to jar artifacts with no classifier. This allows us to shorthand the identity set to {groupId, artifactId}, since the default for the type field is jar, and the default classifier is null.” [https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html ]
Thus, all the sub-elements (scope, exclusions etc.,) of a dependency element--other than groupId, artifactId, type, classifier, not just version--are available for lockdown/default at the point (and thus inherited from there onward) you specify the dependency within a dependencyElement. If you’d specified a dependency with the type and classifier sub-elements (see the first-cited webpage to check all sub-elements) as not jar and not null respectively, you’d need {groupId, artifactId, classifier, type} to reference (resolve) that dependency at any point in an inheritance originating from the dependencyManagement element. Else, {groupId, artifactId} would suffice if you do not intend to override the defaults for classifier and type (jar and null respectively). So default is a good keyword in that definition; any sub-element(s) (other than groupId, artifactId, classifier and type, of course) explicitly assigned value(s) at the point you reference a dependency override the defaults in the dependencyManagement element.
So, any dependency element outside of dependencyManagement, whether as a reference to some dependencyManagement element or as a standalone is immediately resolved (i.e. installed to the local repository and available for classpaths).
I do not recommend using dependencyManagement.
The only benefit of using it is that you can define the version in parent pom and do not need to define it again in child pom. But if you have a set of projects (especially micro-service projects). Using dependencyManagement has no benefits.
Different projects may need different dependency. Why inherit it from the same parent pom. Keep it as simple as possible. If one project needs A dependency, then add it to the pom file. Don't confuse developers.
In Eclipse, there is one more feature in the dependencyManagement. When dependencies is used without it, the unfound dependencies are noticed in the pom file. If dependencyManagement is used, the unresolved dependencies remain unnoticed in the pom file and errors appear only in the java files. (imports and such...)
One use case of <dependencyManagement> is for resolving library versions conflict.
Example:
Project A have library x:1.0.1
Project A have B library
B library have library x:1.0.0
Having this set you will get conflict having project A both x:1.0.1 and x:1.0.0.
To resolve this you can put dependency with specific version into <dependencyManagement> tag
If you have a parent-pom anyways, then in my opinion using <dependencyManagement> just for controlling the version (and maybe scope) is a waste of space and confuses junior developers.
You will probably have properties for versions anyways, in some kind of parent-pom file. Why not just use this properties in the child pom's? That way you can still update a version in the property (within parent-pom) for all child projects at once. That has the same effect as <dependencyManagement> just without <dependencyManagement>.
In my opinion, <dependencyManagement> should be used for "real" management of dependencies, like exclusions and the like.
It was explained by here to be easy to understand.
The conclusion difference between dependencyManagement & dependencies are declaration and actually addition

How should I exclude the wrong version of a provided jar?

I'm having some problems with conflicting versions of some jars. I have a dependency on a library group-a:artifact-a:0.0.1 that has a dependency on group-b:artifact-b:0.0.1, but I don't want that group-b:artifact-b:0.0.1 to be included given that I know that at runtime there will be group-b:artifact-b:0.0.2.
How do I have to write the pom.xml file?
Is this one of the following correct? And what's the difference between these?
Solution 1:
Exclude group-b:artifact-b from group-a:artifact-a:0.0.1:
<dependencies>
<dependency>
<groupId>group-a</groupId>
<artifactId>artifact-a</artifactId>
<version>0.0.1</version>
<exclusions>
<exclusion>
<groupId>group-b</groupId>
<artifactId>artifact-b</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
Solution 2:
Add group-b:artifact-b dependency as provided:
<dependencies>
<dependency>
<groupId>group-b</groupId>
<artifactId>artifact-b</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>group-a</groupId>
<artifactId>artifact-a</artifactId>
<version>0.0.1</version>
</dependency>
</dependencies>
Solution 3:
Add group-b:artifact-b dependency as runtime:
<dependencies>
<dependency>
<groupId>group-b</groupId>
<artifactId>artifact-b</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>group-a</groupId>
<artifactId>artifact-a</artifactId>
<version>0.0.1</version>
</dependency>
</dependencies>
Solution 4:
Add group-b:artifact-b dependency as provided or runtime and exclude it from group-a:artifact-a:0.0.1.
UPDATE:
Sorry for not being explicit, but yes #Tunaki's assumption is correct, the dependency group-b:artifact-b:0.0.2 is not required at compile time.
Option 5: Just declare the version explicitly in your POM.
Maven will overwrite the transitive dependencies if you explicitly declare them in the pom. You don't need to do any mucking about with provided or runtime scope.
According to the docs (emphasis mine):
Dependency mediation - this determines what version of a dependency will be used when multiple versions of an artifact are encountered. Currently, Maven 2.0 only supports using the "nearest definition" which means that it will use the version of the closest dependency to your project in the tree of dependencies. You can always guarantee a version by declaring it explicitly in your project's POM. 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 your pom should just be:
<dependencies>
<dependency>
<groupId>group-b</groupId>
<artifactId>artifact-b</artifactId>
<version>0.0.2</version>
</dependency>
<dependency>
<groupId>group-a</groupId>
<artifactId>artifact-a</artifactId>
<version>0.0.1</version>
</dependency>
</dependencies>
You should use solution 4. Let's go through each solution:
Solution 1
This is using the exclusions principle of Maven. Maven resolves dependencies transitively. But when you do not want a specific transitive dependency to be included in your classpath, you can exclude it using this mechanism.
The excluded dependency will not be used at compile-time or run-time.
But this is not what you want, since you know that your project requires group-b:artifact-b at run-time. In this scenario, the pom.xml does not declare it.
Solution 2
You are using the provided scope. provided in Maven means that this dependency is required at compile-time but should not be included in the final artifact. Typically, this dependency will be provided at run-time by a container, such as a web server.
As such, Maven will override the transitive dependency group-b:artifact-b:0.0.1 of group-a:artifact-a. In the final dependency tree, group-b:artifact-b:0.0.2 will be resolved as a provided dependency and will not be included in the final artifact (for example, if building a war, this library will not end up in WEB-INF/lib).
Solution 3
This time, you are using the runtime scope. This is much like Solution 2.
The difference is that in the final dependency tree, group-b:artifact-b:0.0.2 will be resolved as a run-time dependency and will be included in the final artifact (for example, if building a war, this library will end up in WEB-INF/lib).
Solution 4
This is the same as solution 2 and 3. The difference is that Maven will not override the dependency since you are explicitely excluding it from the list of transitive dependencies of artifact-a. But the result will be the same.
What is the correct solution?
This really depends on how your dependency will be present at run-rime. If it provided by a container, you should use Solution 4 with the provided scope. If not, you should use Solution 4 with the runtime scope.
I am suggesting this solution because:
You are explicitely excluding the unwanted dependency from artifact-a transitive dependency: this makes it more clear that that specific dependency should not be used in the project.
You are explicitely including the wanted dependency in the right scope and the right version. Again, this makes the pom.xml easier to read and to understand.
<dependencies>
<dependency>
<groupId>group-a</groupId>
<artifactId>artifact-a</artifactId>
<version>0.0.1</version>
<exclusions>
<exclusion>
<groupId>group-b</groupId>
<artifactId>artifact-b</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>group-b</groupId>
<artifactId>artifact-b</artifactId>
<version>0.0.2</version>
<scope>provided</scope> <!-- or runtime, depending on your specific case -->
</dependency>
</dependencies>

How to exclude jars during overlay

I have two applications - A and B.
In Application A there are some jars say J1,J2,J3.
And in Application B there is overlay and dependency of Application A. But I don't want jar J2 in application B.
How to exclude jar J2 ?
What you are asking for isn't possible. If Application B has dependencies on application A; and A depends on J2 - how do you think you can run "B" without providing J2?
The only thing that can work: if you can further slice your applications; it might be possible to come up with some component B'; where B' depends on A'; and A' does not depend on J2. Then you can package B' without J2.
You can use the Maven dependency exclusions as described here:
<project>
...
<dependencies>
<dependency>
<groupId>sample.ProjectA</groupId>
<artifactId>Project-A</artifactId>
<version>1.0</version>
<scope>compile</scope>
<exclusions>
<exclusion> <!-- declare the exclusion here -->
<groupId>sample.ProjectB</groupId>
<artifactId>Project-B</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>
However, bear in mind that you might face ClassNotFoundExceptions at runtime if the class required is no longer present.

maven scope for woven artifacts

I have a project foo-instrumented that depends on foo.
This project actually instruments foo with additional code, and replaces it. That is, foo is a compile-time dependency of foo-instrumented but it is definitely not a runtime dependency (foo-instrumented replaces foo), and it should not be propagated to children (that is, projects depending on foo-instrumented should not end up depending on foo).
Is there an appropriate maven scope for that kind of dependency, or another solution?
Edit: I am not being clear enough with my request: although foo should not end up in the children project dependencies, foo's dependencies should (e.g. if foo depends on log4j, then a project that depends on foo-instrumented should have log4j as part of its dependencies), which seems to rule out the provided scope.
Thanks!
Edit: Okay, I need to have a little rant here: DID ANY REAL, ACTUAL HUMAN BEING ACTUALLY UNDERSTAND THE MAVEN DOCS? I had a look at a few pages and guess what: no explanations, no illustrations, JUST TONS OF XML VOMIT. XML VOMIT IS NOT DOCUMENTATION, PEOPLE!
You should use the import scope. In your foo-instrumented project:
<dependencies>
<dependency>
<groupId>bar</groupId>
<artifactId>foo</artifactId>
<type>pom</type>
<scope>import</scope>
<dependency>
<dependencies>
This will pull the dependencies of foo into foo-instrumented without also including foo.
You cannot exclude a dependency, but still include it's dependencies.
However, you can define an exclusion for your non-instrumented dependency and add the dependencies over to your other module (again). When you define the dependency to foo-instrumented, do:
<dependencies>
<dependency>
<groupId>bar</groupId>
<artifactId>foo-instrumented</artifactId>
<exclusions>
<exclusion>
<groupId>bar</groupId>
<!-- Exclude the non-instrumented dependency: -->
<artifactId>foo</artifactId>
</exclusion>
</exclusions>
<dependency>
<!-- Add the dependencies you need for foo to work here -->
<dependencies>

Categories