I am trying to convert and old non-maven java NetBeans project to a maven project. The existing project has 36 libraries.
What I did
I outputted the library folder content to a file and got the list of all the jars.
I searched for the jar in maven repo and added the specific version as dependency in pom
The Result
The new maven project now has some new jars which the old one didn't have, probably they are added because they were the dependencies of the ones I added.
My Questions
If the extra jars that are added in the "Dependencies" section are
required by the jars that I added, how was the old project running?
i.e. without those jars included?
Some of the jars in the old project I believe were the dependencies of other jars. This I figured out when I added a jar and it added another jar by itself which I was about to add. So how do I figure out which jar is the
dependency of which one so I don't explicitly specify that one in my
pom? or so I could add them in sequence.
EDIT:
Thanks to #SubOptimal, i was able to check the graph, but here is what I get:
On the left is the old project opened with all the libraries, on the right, is the newly maven converted project's graph opened. Now you can see the library is the same "axis2-kernel-1.6.1.jar". On the left, the old project doesn't have the geronimo-ws-metadata_2.0_spec which is shown as a dependency of the axis2 library.
Now my question is the same, how was the old project working, is this an optional dependency?
The new dependencies might be there because of different library version in the old non-maven project and the new maven project.
Assume the non-maven project would have used JUnit in version 3.8.
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>sub.optimal</groupId>
<artifactId>foo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8</version>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
</project>
in this example you would have only JUnit as dependency
mvn dependency:tree
output
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) # suboptimal ---
[INFO] com.example:suboptimal:jar:0.0.1-SNAPSHOT
[INFO] \- junit:junit:jar:3.8:test
If you now in the maven project would use version 4.12 (instead of the previous 3.8) you would see following dependencies (after changing the version number in the pom.xml)
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
output would be
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) # suboptimal ---
[INFO] com.example:suboptimal:jar:0.0.1-SNAPSHOT
[INFO] \- junit:junit:jar:4.12:test
[INFO] \- org.hamcrest:hamcrest-core:jar:1.3:test
For the shown dependency junit:junit:jar:4.12:test the test means it's not a runtime dependency. It's need to run the provided tests.
In Netbeans you would see now both as a test dependency
There is another way to show the dependencies directly in Netbeans. When you open the pom.xml click on Graph and only for the first time after you open it on Show Graph.
You get a visual dependency tree
edit: You have not yet said what your old project uses. But find one example for the axis2 kernel below.
When your new project add following dependency
<dependency>
<groupId>org.apache.axis2</groupId>
<artifactId>axis2-kernel</artifactId>
<version>1.6.1</version>
</dependency>
listing the dependencies with mvn dependency:tree reveals following compile time dependencies (needed also for the runtime, see Maven dependency scopes)
[INFO] \- org.apache.axis2:axis2-kernel:jar:1.6.1:compile
[INFO] +- org.apache.ws.commons.axiom:axiom-api:jar:1.2.12:compile
[INFO] | +- org.apache.geronimo.specs:geronimo-activation_1.1_spec:jar:1.0.2:compile
[INFO] | +- org.apache.geronimo.specs:geronimo-javamail_1.4_spec:jar:1.6:compile
[INFO] | +- jaxen:jaxen:jar:1.1.1:compile
[INFO] | \- org.apache.geronimo.specs:geronimo-stax-api_1.0_spec:jar:1.0.1:compile
[INFO] +- org.apache.ws.commons.axiom:axiom-impl:jar:1.2.12:compile
[INFO] | \- org.codehaus.woodstox:wstx-asl:jar:3.2.9:compile
[INFO] +- org.apache.geronimo.specs:geronimo-ws-metadata_2.0_spec:jar:1.1.2:compile
[INFO] +- org.apache.geronimo.specs:geronimo-jta_1.1_spec:jar:1.1:compile
[INFO] +- javax.servlet:servlet-api:jar:2.3:compile
[INFO] +- commons-httpclient:commons-httpclient:jar:3.1:compile
[INFO] | \- commons-codec:commons-codec:jar:1.2:compile
[INFO] +- commons-fileupload:commons-fileupload:jar:1.2:compile
[INFO] +- wsdl4j:wsdl4j:jar:1.6.2:compile
[INFO] +- org.apache.ws.commons.schema:XmlSchema:jar:1.4.7:compile
[INFO] +- org.apache.neethi:neethi:jar:3.0.1:compile
[INFO] +- org.apache.woden:woden-api:jar:1.0M9:compile
[INFO] +- org.apache.woden:woden-impl-dom:jar:1.0M9:compile
[INFO] | \- org.apache.woden:woden-impl-commons:jar:1.0M9:compile
[INFO] +- commons-logging:commons-logging:jar:1.1.1:compile
[INFO] \- javax.ws.rs:jsr311-api:jar:1.0:compile
So why it looks now your old project was not needing them? Assuming that your old project uses the axis2.war file (extracted from axis2-1.6.1-war.zip). The dependencies are embedded.
jar -tf axis2.war | grep geronimo-ws-metadata
output
WEB-INF/lib/geronimo-ws-metadata-LICENSE.txt
WEB-INF/lib/geronimo-ws-metadata_2.0_spec-1.1.2.jar
Related
Given a very simple Maven project with a single pom-file containing a single dependency:
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>maven-test</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.apache.cxf.xjc-utils</groupId>
<artifactId>cxf-xjc-runtime</artifactId>
<version>3.3.0</version>
</dependency>
</dependencies>
</project>
When running mvn dependency:tree different results are given depending on Java version.
With Java 8:
[INFO] Scanning for projects...
[INFO]
[INFO] -----------------------< org.example:maven-test >-----------------------
[INFO] Building maven-test 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) # maven-test ---
[INFO] org.example:maven-test:jar:1.0-SNAPSHOT
[INFO] \- org.apache.cxf.xjc-utils:cxf-xjc-runtime:jar:3.3.0:compile
[INFO] \- jakarta.xml.bind:jakarta.xml.bind-api:jar:2.3.2:compile
[INFO] \- jakarta.activation:jakarta.activation-api:jar:1.2.1:compile
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.982 s
[INFO] Finished at: 2020-06-22T15:05:56+02:00
[INFO] ------------------------------------------------------------------------
With Java 11:
[INFO] Scanning for projects...
[INFO]
[INFO] -----------------------< org.example:maven-test >-----------------------
[INFO] Building maven-test 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) # maven-test ---
[INFO] org.example:maven-test:jar:1.0-SNAPSHOT
[INFO] \- org.apache.cxf.xjc-utils:cxf-xjc-runtime:jar:3.3.0:compile
[INFO] +- jakarta.xml.bind:jakarta.xml.bind-api:jar:2.3.2:compile
[INFO] | \- jakarta.activation:jakarta.activation-api:jar:1.2.1:compile
[INFO] +- javax.annotation:javax.annotation-api:jar:1.3.1:compile <-- This and below only with Java 11
[INFO] +- javax.xml.ws:jaxws-api:jar:2.3.0:compile
[INFO] | +- javax.xml.bind:jaxb-api:jar:2.3.0:compile
[INFO] | \- javax.xml.soap:javax.xml.soap-api:jar:1.4.0:compile
[INFO] \- javax.activation:activation:jar:1.1.1:compile
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.261 s
[INFO] Finished at: 2020-06-22T15:05:51+02:00
[INFO] ------------------------------------------------------------------------
I would have expected the trees to be the same under the two Java versions.
Maven version is 3.6.0.
Why do the resolved dependencies differ between the Java versions?
The reason why the dependency tree differs between the Java versions is found in the dependency:
<dependency>
<groupId>org.apache.cxf.xjc-utils</groupId>
<artifactId>cxf-xjc-runtime</artifactId>
<version>3.3.0</version>
</dependency>
This in turn has xjc-utils as its parent:
<parent>
<groupId>org.apache.cxf.xjc-utils</groupId>
<artifactId>xjc-utils</artifactId>
<version>3.3.0</version>
</parent>
In this POM file, we find the dependencies that are excluded when building with Java 8:
<profile>
<id>java9-plus</id>
<activation>
<jdk>[9,)</jdk>
</activation>
<dependencies>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>javax.xml.ws</groupId>
<artifactId>jaxws-api</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
</dependencies>
</profile>
This pretty much speacks for itself, the dependencies will only be included if Java 9 or above is used, as stated in this range: <jdk>[9,)</jdk>. The documentation for the tag states:
Specifies that this profile will be activated when a matching JDK is detected. For example, 1.4 only activates on JDKs versioned 1.4, while !1.4 matches any JDK that is not version 1.4.
This activation profile makes sure these dependencies are included when Java 11 is used:
[INFO] +- javax.annotation:javax.annotation-api:jar:1.3.1:compile
[INFO] +- javax.xml.ws:jaxws-api:jar:2.3.0:compile
[INFO] | +- javax.xml.bind:jaxb-api:jar:2.3.0:compile
[INFO] | \- javax.xml.soap:javax.xml.soap-api:jar:1.4.0:compile
[INFO] \- javax.activation:activation:jar:1.1.1:compile
More info about activation can be found in the official Maven documentation:
Activations are the key of a profile. The power of a profile comes from its ability to modify the basic POM only under certain circumstances. Those circumstances are specified via an activation element.
Together with another example of activation based on Java version:
<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
https://maven.apache.org/xsd/maven-4.0.0.xsd">
...
<profiles>
<profile>
<id>test</id>
<activation>
<activeByDefault>false</activeByDefault>
<jdk>1.5</jdk>
<os>
<name>Windows XP</name>
<family>Windows</family>
<arch>x86</arch>
<version>5.1.2600</version>
</os>
<property>
<name>sparrow-type</name>
<value>African</value>
</property>
<file>
<exists>${basedir}/file2.properties</exists>
<missing>${basedir}/file1.properties</missing>
</file>
</activation>
...
</profile>
</profiles>
</project>
Dependency tree mojo trims lower level dependencies if the dependency is already present higher in the tree.
We can use verbose flag (-Dverbose) to show the excluded dependencies.
To find a specific artifact : mvn dependency:tree -Dverbose -Dincludes=[groupId]:[artifactId]:[type]:[version]
Please visit Maven Dependency Tree to know more.
I have a project A, which has B and C dependencies.
The project B also depends on C.
In project A pom, I have:
<dependencyManagement>
<dependency>
<groupId>br.com.mygroup</groupId>
<artifactId>C</artifactId>
<version>2</version>
</dependency>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>br.com.mygroup</groupId>
<artifactId>B</artifactId>
<version>BVERSION</version>
</dependency>
<dependency>
<groupId>br.com.mygroup</groupId>
<artifactId>C</artifactId>
<version>2</version>
</dependency>
<dependencies>
In project B(version BVERSION), I have:
<dependencies>
<dependency>
<groupId>br.com.mygroup</groupId>
<artifactId>C</artifactId>
<version>1</version>
</dependency>
</dependencies>
I have added some methods in C dependency in version 2, but the code doesn't compile when I try to use the new methods. That is, I can't access the new methods. Project A is using version 1(which is inside project B) of C.
If I change the order of the import in project A pom from B, C to C, B, the code compiles, but at execution time a get java.lang.NoSuchMethodError error.
Shouldn't maven dependencyManagement deal with this problem and force project A to use version 2 of C? Does anyone have an idea of what I am getting wrong?
EDIT 1:
mvn dependency:tree returns the following:
[INFO] br.com.mygroup:A:1.0-SNAPSHOT
[INFO] +- br.com.mygroup:B:jar:BVERSION:compile
[INFO] +- br.com.mygroup:C:jar:2:compile
EDIT 2:
mvn dependency:list returns the following:
[INFO] Scanning for projects...
[INFO]
[INFO] --------------------< br.com.mygroup:A >---------------------
[INFO] Building A 1.0-SNAPSHOT
[INFO] --------------------------------[ war ]---------------------------------
[INFO]
[INFO] --- maven-dependency-plugin:2.8:list (default-cli) # A ---
[INFO]
[INFO] The following files have been resolved:
[INFO] br.com.mygroup:B:jar:BVERSION:compile
[INFO] br.com.mygroup:C:jar:2:compile
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.639 s
[INFO] Finished at: 2019-10-04T09:03:37-03:00
[INFO] ------------------------------------------------------------------------
I have a maven project with these dependencies:
<dependencies>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.4-1200-jdbc41</version>
<exclusions>
<exclusion>
<groupId>org.slf4</groupId>
<artifactId>slf4j-simple</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
If I run mvn tree it still shows the excluded artifact:
$ mvn dependency:tree
...
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) # testArtifact ---
[INFO] testGroup:testArtifact:jar:1.0-SNAPSHOT
[INFO] \- org.postgresql:postgresql:jar:9.4-1200-jdbc41:compile
[INFO] +- com.github.dblock.waffle:waffle-jna:jar:1.7:runtime
[INFO] | +- net.java.dev.jna:jna:jar:4.1.0:runtime
[INFO] | +- net.java.dev.jna:jna-platform:jar:4.1.0:runtime
[INFO] | +- org.slf4j:slf4j-api:jar:1.7.7:runtime
[INFO] | \- com.google.guava:guava:jar:18.0:runtime
[INFO] \- org.slf4j:slf4j-simple:jar:1.7.7:runtime ** <--- BAD ONE
And if I run things like dependency:copy-dependencies or the shaded jar plugin, they all pull in the unwanted jar.
Am I missing something?
Using maven 3.6.0
The groupId is incorrect. Should be org.slf4j instead of org.slf4 (the j is missing).
I have a project that at one point had these lines about jdk.tools
<dependency>
<groupId>jdk.tools</groupId>
<artifactId>jdk.tools</artifactId>
<scope>system</scope>
<version>1.8.0</version>
<systemPath>${java.home}/../lib/tools.jar</systemPath>
</dependency>
On my Eclipse, removing these lines would gave me an error of
"Missing artifact jdk.tools:jdk.tools:jar:1.8".
But my colleague used the same pom.xml (without those lines) and she did not see
the error.
Also, on a UNIX machine I could maven build without needing
those lines (this is expected, because the scope has been system).
The dependency tree related to this artifact is this:
[INFO] +- org.apache.hadoop:hadoop-common:jar:2.7.3:compile
[INFO] | +- org.apache.hadoop:hadoop-annotations:jar:2.7.3:compile
[INFO] | | \- jdk.tools:jdk.tools:jar:1.8:system
I have added vaadin-client-compiler dependency as a provided scope dependency in my vaadin application pom.
As I have read, provided dependency is not transitive, so the dependencies of vaadin-client-compiler should become dependencies of my webapp.
But, I found dependencies of vaadin-client-compiler (commons-lang3-3.1.jar) inside my WEB-INF/lib directory.
Also, these dependencies are shown in mvn dependency:tree output as well.
[INFO] | +- javax.validation:validation-api:jar:1.0.0.GA:compile
[INFO] | \- javax.validation:validation-api:jar:sources:1.0.0.GA:compile
[INFO] +- com.vaadin:vaadin-client-compiler:jar:7.6.4:provided
[INFO] | +- com.vaadin:vaadin-sass-compiler:jar:0.9.13:compile
[INFO] | | \- com.yahoo.platform.yui:yuicompressor:jar:2.4.8:compile
[INFO] | | \- rhino:js:jar:1.7R2:compile
[INFO] | +- commons-collections:commons-collections:jar:3.2.2:compile
................................................
.................................................
[INFO] | +- commons-codec:commons-codec:jar:1.8:compile
[INFO] | +- commons-io:commons-io:jar:2.4:compile
[INFO] | +- org.apache.commons:commons-lang3:jar:3.1:compile
Question: Why did dependencies of a provided scope dependency became dependencies of my webapp?
Indeed, according to official Maven Dependency Mediation, the provided scope would bring in its transitive dependencies as following:
Transitive dependencies in compile scope > would be fetched as provided scope
Transitive dependencies in provided scope > ignored
Transitive dependencies in runtime scope > would be fetched as provided scope
Transitive dependencies in test scope > ignored
Hence, transitive dependencies of a provided dependency would either be ignored or be imported as provided as well and as such no part of the final packaged war.
Adding the following dependency to a sample project:
<dependencies>
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-client-compiler</artifactId>
<version>7.6.4</version>
<scope>provided</scope>
</dependency>
</dependencies>
Would lead to the following, executing:
mvn dependency:tree -Dincludes=com.vaadin
We would have as part of the output:
[INFO] \- com.vaadin:vaadin-client-compiler:jar:7.6.4:provided
[INFO] +- com.vaadin:vaadin-shared:jar:7.6.4:provided
[INFO] +- com.vaadin:vaadin-server:jar:7.6.4:provided
[INFO] +- com.vaadin:vaadin-client:jar:7.6.4:provided
[INFO] +- com.vaadin:vaadin-sass-compiler:jar:0.9.13:provided
[INFO] \- com.vaadin:vaadin-client-compiler-deps:jar:1.2.0:provided
Perfectly consistent with the documentation.
However, if we add to the pom.xml file the following:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-server</artifactId>
<version>7.6.4</version>
<scope>compile</scope>
</dependency>
</dependencies>
</dependencyManagement>
Note: we are overriding the scope of one of its transitive dependencies to compile.
Re-executing the previous command we would have:
[INFO] \- com.vaadin:vaadin-client-compiler:jar:7.6.4:provided
[INFO] +- com.vaadin:vaadin-shared:jar:7.6.4:compile
[INFO] +- com.vaadin:vaadin-server:jar:7.6.4:compile
[INFO] +- com.vaadin:vaadin-client:jar:7.6.4:provided
[INFO] +- com.vaadin:vaadin-sass-compiler:jar:0.9.13:compile
[INFO] \- com.vaadin:vaadin-client-compiler-deps:jar:1.2.0:provided
Which means: the transitive dependency vaadin-server is still brought in by vaadin-client-compiler, but its scope is now at compile as per dependency management.
Hence, you should:
Check whether your pom.xml defines any dependencyManagement section
Check whether your parent pom or any pom in the hierarchy would do so, executing mvn help:effective-pom -Doutput=full-pom.xml would definitely help
Check whether any active profile would also influence the build, executing mvn help:active-profiles would also help
The "non-transitivity" of provided dependencies is tricky. It only means that the provided dependencies of your dependencies are not pulled. On the other hand, compile dependencies of provided dependencies are pulled (as you have experienced). The full truth is in the table shown in:
https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html