The right way to use maven - maven

I'm new to maven, I got 2 problems here:
1,How to solve missing artifact problem?
I need jcharts-0.7.5, but it's not available in Maven Central Repository. I have the jar file, but seems not easy to put it into a maven project.
2,How to fix wrong dependency scope of artifact?
I have a WAR project depends on artifact axis2-kernel, which is depending on servlet-api-2.3 with the scope of 'compile' (mistake of 'provided'), so mvn install packet the servlet-api-2.3.jar into the war file, and causes a "validateJarFile(...) - jar not loaded." error in Tomcat 7.

Number one: use a maven repository. This can be a simple Apache HTTP site with static content. But I would recommend using Sonatype Nexus or JFrog Artifactory for storing artifacts not found somewhere else.
You may find them in the JBoss repository or IBiblio (both quite big)
Number two: you can add that dependency to your pom and just set the scope you want. If you exclude the artifact you will have to add it again anyway. Maven will always prefer what is directly in you pom:
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<scope>provided</scope>
</dependency>

To answer your second question: you can exclude transitive dependencies using the < exclusion > tag: http://maven.apache.org/guides/introduction/introduction-to-optional-and-excludes-dependencies.html
<project>
...
<dependencies>
<dependency>
<groupId>org.apache.axis2</groupId>
<artifactId>axis2-kernel</artifactId>
<version>...</version>
<exclusions>
<exclusion><!-- declare the exclusion here -->
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>

There are many different solutions how to add missing dependencies. For example, you could use the scope system and provide the path (you can put the JAR into the project and use a path relative to ${basedir}).
But a much better solution is to install a server like Nexus or Artifactory because they allow you to create your own repositories and they still work should the Internet fail (for example, when some idiot breaks your router or your ISP has some problems or someone drives a 18 inch double-T steel beam through a bunch of fibres).
Builds will also be much faster since the downloads will be via your local LAN instead of going around half the globe.
You can simply repeat the dependency in your POM with a different scope (your POM always wins) or you can use a dependencyManagement element.
I prefer the dependencyManagement approach because it allows you to set scopes and versions in a single place for all your projects.

Related

Getting Maven to resolve missing dependencies with closest available matches

When I look at my local Maven cache (~/.m2/repository/) I see 10-20 versions of certain artifacts, some of which are being used for only a single specific build (project). I would like to get rid of this duplication (true, they are different versions, but I'd still think a depending project would be able to tolerate a micro or minor version difference) and to somehow ask Maven to resort to the closest available version during dependency resolution, if a specific artifact version is missing in the local repository.
For example, if I have versions 1.0.0, 1.1.2, 1.4.0 and 2.0.0 of a foo:bar artifact in my local cache, I would like Maven to:
use 1.1.2 for a build requiring 1.1.0
use 1.4.0 for a build requiring 1.4.10
use 2.0.0 for a build requiring 2.5.0
without having to manually change the pom of the specific build(s).
I am fairly aware of the risks associated with switching dependency versions without proper analysis, and I'm only asking for a mechanism to be utilized for non-critical builds (such as a tool/library that I just cloned off a VCS, and would like to run and try out), preferably activated only when a particular flag is provided.
Is there something out there, like a Maven extension or plugin (that can be applied on a system-wide scale, and activated on demand with a flag), that can help me achieve my goal?
P.S.: Since the definition of "closest" could be ambiguous (given the fact that Maven may not know which of 1.4.0 and 2.0.0 is closer to 1.5.0 depending on the actual release versions lying between them), it would even be sufficient if I can specify the version on the build command (e.g. mvn package -Dfoo:bar=1.4.0), still without making any manual pom changes. (While this may already be possible for versions that have been specified as <properties> entries, I would like a generic solution where even hard-coded versions in transitive dependencies could be overridden.)
P.P.S.: Please note tht the project(s) that would be built would not have been authored/composed by me, so I don't really have control/authority over their actual pom files. What I'm looking for is a way to override dependency versions in their pom files without doing any manual modifications at source level.
In order to change a transitive dependency, you need to exclude the transitive dependency in your direct dependency, then add a direct dependency in your pom.
For example, if you have a dependency on foo.jar (which depends on xyz.jar version 1.3) and on bar.jar (which depends on xyz.jar version 1.4), you can have these two sections in your pom:
<!-- Define the version(s) that you allow your dependencies to depend on. -->
<dependencyManagement>
<dependency>
<groupId>projectXyz</groupId>
<artifactId>xyz</artifactId>
<version>[1.0,2.0)</version>
</dependency>
<dependency>
<groupId>projectFoo</groupId>
<artifactId>foo</artifactId>
<version>1</version>
<exclusions>
<exclusion>
<groupId>projectXyz</groupId>
<artifactId>xyz</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>projectBar</groupId>
<artifactId>bar</artifactId>
<version>5</version>
<exclusions>
<exclusion>
<groupId>projectXyz</groupId>
<artifactId>xyz</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencyManagement>
...
<!-- Declare your dependencies but don't allow them to suck in their transitive dependencies. -->
<dependencies>
<dependency>
<groupId>projectXyz</groupId>
<artifactId>xyz</artifactId>
</dependency>
<dependency>
<groupId>projectFoo</groupId>
<artifactId>foo</artifactId>
</dependency>
<dependency>
<groupId>projectBar</groupId>
<artifactId>bar</artifactId>
</dependency>
</dependencies>
...
This will pick up the most recent version of xyz.jar that it can, and that will be the only version used. When foo and bar use xyz, they'll have the version that you've allowed into your project.
The best thing to do is to use a parent pom (or bom: bill of materials) with a well-defined and well-maintained dependencyManagement section. Stick with a single version of everything, just share that "everything" between all projects. You can override versions in projects if you need to.
If you'd rather define versions in each project, then version ranges will work. For the three examples you gave, you would use things like:
[1.1.0, 1.2)
[1.4.0, 1.5)
[2.0.0,)
(Open to correction here.. I haven't used version ranges in almost 10 years.)
Finally, to get it to use versions that are already available, rather than download the best ones, all you can do is to use a local artifact repository as your central maven repository, and turn off access to maven central and bintray.
Closest thing I found so far: https://github.com/jboss/maven-dependency-management-extension/blob/master/README.md
It can be dropped into ${MAVEN_HOME}/lib/ext and utilized for overriding versions of specific dependencies, e.g. mvn install -Dversion:junit:junit=4.10. While it doesn't offer the suggested "intelligent version derivation" approach, it's a good-enough solution.

Excluding transitive dependency not working

Project A references Project B. Project B has included a local dependency. This local dependency unfortunately has a dependency to net.java.dev.designgridlayout in version 1.5.
We want to use net.java.dev.designgridlayout in version 1.11 in Project A but we are not able to "overwrite" the dependency. Eclipse always uses the dependency from Project B.
We already tried to exclude the 1.5 version from the local dependency, but it doesn't work.
The strange thing is, that Eclipse successfully resolves a class that has been added with version 1.11. For an already existing class, however, eclipse resolves it from the transitive dependency from de.someCompany.
Project B:
<dependencies>
<dependency>
<groupId>de.someCompany</groupId>
<artifactId>fs-client</artifactId>
<version>5.1.209</version>
<exclusions>
<exclusion>
<groupId>net.java.dev.designgridlayout</groupId>
<artifactId>designgridlayout</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>net.java.dev.designgridlayout</groupId>
<artifactId>designgridlayout</artifactId>
<version>1.11</version>
</dependency>
</dependencies>
Project A:
<dependencies>
<dependency>
<groupId>Project-B</groupId>
<artifactId>Project-B</artifactId>
<version>1503.01</version>
</dependency>
</dependencies>
I also tried to include the 1.11 dependency in Project A.
We even tried to install the DesignGridLayout V. 1.11 in the local dependency and to change the groupID and artifactId to something different, but it cannot even be found by Eclipse for some reason. If it would be possible to include the DesignGridLayout with another groupId and artifactId, I think it would work.
mvn install:install-file -Dfile=lib\designgridlayout.jar -DgroupId=com.company.designgridlayout -DartifactId=design-grid-layout -Dversion=1.11 -DgeneratePom=true -Dpackaging=jar -DlocalRepositoryPath="%USERPROFILE%\.m2\repository"
Not sure - but:
Your project A has a dependency to itself? Shouldn't it use project-b?
Its not a good idea to change group or artifact id's as maven can no longer detect its the same artifact. If you do a custom version the version number should be enough.
If you add the dependency in your own pom then you don't need to exclude the artifact, since the groupId and artifactId are the same. The version in your own pom will win in project-b. If project a defines that dependency again itself that version will win.
I would do a mvn dependency:tree on project-a pom to see where the dependencies come from.
For eclipse: it indexes the local repository. In the maven settings there is a re-index button. So if you manually copy jars in there that may help eclipse to find the artifact. But that workaround would need to be done on every machine. I would not count that as solution. In the maven world artifact-resolution is an infrastructure issue and should not be handled per project. The way this is done should be transparent through the settings.xml

Nexus sonatype does not get zip dependency

I have setup Sonatype Nexus with Maven and seems to be working. However, my project depends (transitively) on docbook-xsl-1.75.2 but instead of a jar there you find a zip file. Is this the reason why Nexus is not getting it, that it is a zip file? I haven't found any Nexus configuration page in the web console offering a possible filter.
I browse my Nexus repository and see it gets the pom file but nothing else.
That module has no main artifact, it's packaging type is set to "pom".
What it does have is two additional artifacts which can be retrieved using Maven module classifiers as follows:
<dependency>
<groupId>net.sf.docbook</groupId>
<artifactId>docbook-xsl</artifactId>
<version>1.75.2</version>
<classifier>resources</classifier>
<type>zip</type>
</dependency>
And
<dependency>
<groupId>net.sf.docbook</groupId>
<artifactId>docbook-xsl</artifactId>
<version>1.75.2</version>
<classifier>ns-resources</classifier>
<type>zip</type>
</dependency>
Sorry, I have no idea how you'd retrieve these as transitive dependencies.
The next day, and after restarting Nexus it pulled the dependency. I don't still understand the magic behind Nexus not seeing the dependencies while they are clearly available but at least this question is resolved.

Does Maven need to explicitly specify the dependency that Spring/Hibernate dependented?

I'm new to Maven, I try to use Maven with Spring, Hibernate in my project. After go though the Spring and Hibernate reference, I found that "there is no need to explicitly specify the dependent liberaries in POM.xml file for such Apache commons liberaries".
My questions is that : If my other parts of project refer to Apache commons liberary, such as commons-io, SHOULD I explicit specify this dependency in POM.xml file?
You should define those dependencies in Maven which your project is using. For example, even though some library depends on commons-io but if your code needs this then you should directly define commons-io in your pom.xml
You should not worry about the dependencies of the libraries you have defined in your pom.xml. Maven will do that for you.
Maven is used to avoid the issue of having to run down JAR files that are dependent on other JAR files. Of course you do not HAVE to use maven to do this, but you should. Maven will automatically download the dependent JAR files of the JAR file you require. THe hibernate-entity manager JAR file, for example, has over 100 dependencies and maven does the work for you.
Anyway,even if you do add the commons-io file to the build path/classpath of the maven project,and then update the project configuration, maven will kick it out.
You can provide a lib name on a site like mvnrepository.com to see what it depends on (e.g. take a look at a section called "This artifact depends on ..." in case of spring-webmvc library). Those dependencies (which your artifact depends on) are called transitive dependencies. You don't have to specify these in your pom.xml as maven will resolve them for you.
For the sake of readability you should only state those dependencies in your module that you rely on directly. You want JUnit to test your software, only declare JUnit; you need hibernate to use ORM, declare hibernate, and so on. Leave the rest to Maven.
And most of the time you should state what you intend to use in the very module you want to use it in. So if you want to use a dependency in more than one module, consider moving it into a dependencyManagement block in a parent pom and referencing it from there in the module you want it in.
parent pom.xml
<dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
child pom.xml
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>
This guarantees you version-stability and still allows you to find out what a module uses by only looking in it's pom (and not all over the place).

How to include jar in Maven Netbeans proj that doesnt exist in maven repo

I am using Netbeans to build a Maven project, and have the JTidy java library as a dependency. It turns out JTidy doesnt exist in any maven repos, so I can't just add a "normal" depedency entry for it.
What is the best way of handling dependencies to libraries in Maven projects that arent available on repos?
I've currently tried adding it to my maven pom as such (after copying the jar to my projects /libs folder)
<dependency>
<groupId>org.w3c</groupId>
<artifactId>org.w3c.tidy</artifactId>
<version>9.3.8</version>
<scope>system</scope>
<systemPath>${basedir}/libs/jtidy-r938.jar</systemPath>
</dependency>
However it complains that it will be unresolvable by dependent projects.
First of all, it's under another groupId, that's why you didn't find it.
<dependency>
<groupId>net.sf.jtidy</groupId>
<artifactId>jtidy</artifactId>
<version>r938</version>
</dependency>
Jtidy
But to answer your question, one way of doing this is to manually install it in your local repo as described here.
The best way IMHO is to add it to a proxy like Nexus. That way other people can access it from there without having to install it locally. However, this means you have to set up a repository manager, which doesn't make much sense if you are the only developer on the project.

Resources