I have maven project Main and project Util.
Project Util depends on a third-party library Lib which depends on gwt-dev. gwt-dev causes a lot of conflicts, it is needed for GWT compilation only, so it should be marked as "provided", but it is "compile".
So I should mark Lib as "provided" in Util. But if I do so my Main project won't compile as it cannot find Lib classes.
At the moment I mark Lib as "provided" and then also include it as "provided" in Main. It is inconvenient because I have to remember Util dependencies.
How could I solve this problem?
Use Lib in compile scope and exclude gwt-dev:
<project>
...
<dependencies>
<dependency>
<groupId>Lib group</groupId>
<artifactId>Lib artifact id</artifactId>
<version>Lib version</version>
<scope>compile</scope>
<exclusions>
<exclusion> <!-- declare the exclusion here -->
<groupId>com.google.gwt</groupId>
<artifactId>gwt-dev</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>
Just a remark, excluding is typically a bad practice. In this case, you don't have much choice, since Lib's artifact should have gwt-dev as provided (it's Lib's bug...). So, don't forget to add a decent comment that explains the exclusion.
Related
I have a multi-module project in maven where some of the modules depend on other modules. Now the modules that act as dependencies have some of the dependencies which are already listed in the dependent module's pom.
Is there a quick way to identify such duplicate dependencies and remove them from the dependent module's pom?
A project's dependency tree can be expanded to display dependency conflicts.
Use command
mvn dependency:tree -Dverbose=true
to identify such duplicate dependencies. It shows all duplicates and conflicts in the pom.
Use the <exclusions> tag under the <dependency> section of the pom to exclude such duplicate dependencies.
<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>
If you are using eclipse as IDE then the duplicates can be seen in the dependency hierarchy of the concerned pom.xml. And using exclusions tag they can be ommitted.
You can use mvn depgraph:graph -Dincludes=ets.tkt -DshowDuplicates -Dscope:compile.
To use this plugin put this on your settings.xml
<settings>
. . .
<pluginGroups>
<pluginGroup>com.github.ferstl</pluginGroup>
</pluginGroups>
</settings>
When you run the previous console command, you can go to /target and you will find a .dot file. you can render this file using graphviz.
More info at https://github.com/ferstl/depgraph-maven-plugin
There is a JBoss tool to help with these issues: http://tattletale.jboss.org/
Unfortunately, it seems that is not under active development these days.
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>
I'm following this guide:
https://github.com/maxmind/GeoIP2-java
It says:
We recommend installing this package with Maven. To do this, add the dependency to your pom.xml:
<dependency>
<groupId>com.maxmind.geoip2</groupId>
<artifactId>geoip2</artifactId>
<version>2.2.0</version>
</dependency>
There is also pom.xml file in the Git repository of GeoIP2 which is much longer - what is the difference between them?
Cited from the official homepage:
Apache Maven is a software project management and comprehension tool. Based on the concept of a project object model (POM), Maven can manage a project's build, reporting and documentation from a central piece of information.
Think of the pom.xml as the heart of Maven. In the file you can specify dependencies (most typically jar files), and other information, such as how the project should be built. Without digging to deep into this, one of Maven's strengths is that it manages the dependencies of projects.
To answer your concrete question, GeoIP2 manages its dependencies using Maven. This section of its pom.xml defines them:
<dependencies>
<dependency>
<groupId>com.maxmind.db</groupId>
<artifactId>maxmind-db</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.http-client</groupId>
<artifactId>google-http-client</artifactId>
<version>1.20.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.5.3</version>
</dependency>
</dependencies>
By using Maven in your own project, you will only need to add the one dependency to GeoIP2. Maven will then search for the dependency in a repository, typically the Maven Central Repository if Maven isn't configured to use another. It will also automatically download all other needed dependencies (transitive dependencies), in this case it would be the dependencies listed above, plus any other dependencies those in turn depend on, and so on.
So, a short recap: Without a dependency management tool like Maven, you would need to manually make sure you have all the correct dependencies on the classpath. Maven fixes this for you.
I have prepared some util classes.
I planned to make them as jar and distribute it to required projects.
My util classes uses some already existing custom code provided in the form of jar file.
My code is dependent on "MainUtil.jar" whi internally dependends on Java Servlet, Commons IO, Commons Codec and so on.....
My POM dependency looks as below.
<dependency>
<groupId>com.solutions</groupId>
<artifactId>sol-core</artifactId>
<version>2.3</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-ws-security</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-ws-policy</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk16</artifactId>
<version>1.46</version>
</dependency>
When I package my jar it looks fine.
But when my jar is used in a project where these my util classes are used , I could see a wierd issue.
The commonc-codec jar files are not included in the project package when packaged.
Also code which requies this common-codec is failing.
When I explicitly include the commons-codec dependency, everything works perectly.
My confusion is, why should I explicitly add the codec dependency when I should be resolved by Maven based on the POM of the custom jar files.
And why the issue is happening only with the commons-codec but not with other dependency.
Your code depends on all the other jars. When you create jar for your project the jar file does not contain all the dependent jar classes.
Where ever you are using your jar you have to use other dependent jars. You have not mentioned whether you are using maven there also. If yes then if you have defined dependency then all the dependent jars will be in the classpath.
Issue with you dependency resolving is,
the existing dependency in your project might have some dependency management on this jar. That is the reason, old jar is taking precedence over your custom jar dependency.
Thry adding exclusion in your already existing jar for this common-codec jar.
like
<dependency>
<... Your existing dependency ..>
<exclusions>
<exclusion>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</exclusion>
</exclusions>
</dependency>
Use this command and check how your dependency is being resolved.
mvn dependency:resolve
Then everything should be fine.
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>