views:

615

answers:

3

I have lately become a big fan of Maven for controlling the build cycle for my application. However I've encountered some rough edges with Maven's dependency management. I'm wondering if these are limitations of the tool and paradigm, necessary evils of dependancy management, or if I"m just using the tool incorrectly.

  1. First is the matter of transitive dependencies. As I understand it, if you provide a dependency, Maven will in turn find any dependencies of that dependency. That is great, but for many of my dependencies, this has not worked. For example, including Hibernate in my project:

    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>3.3.2.GA</version>
    </dependency>
    

    Results in a missing dependency of slf4j. I need to manually add this dependency which I assumed would be Maven's job. The same goes for Spring. If I add Spring-MVC as a dependency, shouldn't all of the basic servlet dependencies be added for me (because Spring-MVC would need this stuff)? I'm referring to the servlet, jsp, jstl libraries.

  2. Second is the management of repositories. Maven comes shipped with a default main repository, but I've found that in many cases this repository is not up to date. For example, ifyou want spring3, you have to manually add the springsource repository, and if you want hibernate 3.5+ you have to add the jboss repository. It seems to defeat the point of automatic dependency management when you have to hunt down the correct repositories yourself. This hunting soon gets complicated. For example to add Spring3, you may want the spring release repo, the spring externals repo and the spring milestone repo.

  3. Closely related to number 2 is ensuring you have the correct version of an artifact. I have been burned several times by including the wrong versions of dependent artifacts for a given artifact. For example the wrong version of the servlet/jsp/jstl apis for spring3, or the wrong version of persistence / annotation apis for hibernate. The repositories are filled with many versions, some with confusing names like productx-3.ga, productx-3-rc1, productx-3-SNAPSHOT, productx-3-cr, product-3-beta, etc. Some of these are obvious (rc= release candidate), but it can be confusing trying to determine the order of these versions.

  4. Finally, the issue of the type a dependency. I probably just don't understand this well enough, but many repo artifacts are of type "pom" not "jar". Several times i have added a dependency jar to my project only to find out at build time that the repo jar does not actually exist (example is org.hibernate ejb3-persistence in the jboss repo).

With some experimenting, I can usually get a build to work, but is dependency management in general this complicated? I still prefer this approach to manually adding jar files to my project, but I would be interested to learn how to improve my maven dependency management skills.

+5  A: 

Can't answer all parts of the question, but about some of them:

  • Some transitive dependecies are marked 'optional', so people who don't need these features wouldn't download them, but people, who need, have to set it explicitly in their poms.

  • Maven Central repository contain only releases. Therefore, it doesn't contain Hibernate 3.5 (which is beta) as well as it hadn't contained Spring 3 until it was released (by the way, you don't need to specify specail Spring repository for Spring 3 any more - release is already in Maven Central)

  • slf4j is a very special kind of dependency - its runtime behavior depends on which implementation of slf4j you use. Therefore, to control its behavior you have to specify slf4j implementation explicitly

  • About management skills: to get useful information for maintaining your pom.xml you can use mvn dependency:tree (especially with -Dverbose=true) and mvn dependency:analyze. It can be also useful to look into pom file of your dependency to look at the optional dependencies.

axtavt
cool thanks for the answer. Can you elaborate on the idea of an optional dependancy? To me this isn't clear, either you have teh dependancy or you don't. If you don't have it, than Maven should get it, no? Or is it the case, that some usecases for an artifact don't require that dependancy, in which case there would be little point int including it (for example it would be pointless to include hibernate-annotations if you didn't use annotations in your project).
darren
Optional dependencies are dependencies that are required by a configuration. A network library may declare a pooling library it depends on as an optional dependency; so that only those who want to enable pooling are required to download the extra dependencies.
notnoop
If you use eclipse, the m2eclipse plugin is _really_ good for seeing the dependency tree.
Dominic Mitchell
Central doesn't contain SNAPSHOT but it may contain alpha, beta versions of artifacts. Just one example: http://repo2.maven.org/maven2/org/apache/maven/plugins/maven-assembly-plugin/2.2-beta-5/
Pascal Thivent
+1  A: 

First is the matter of transitive dependencies. As I understand it, if you provide a dependency, Maven will in turn find any dependencies of that dependency. That is great, but for many of my dependencies, this has not worked. (...)

As already pointed out, some dependencies may be marked as optional (and are not pulled transitively). The idea is that some dependencies are only used for certain features and will not be needed if that feature isn't used. If a user wants to use functionality related to an optional dependency, they will have to redeclare that optional dependency in their own project. So this just works as designed :)

Second is the management of repositories. Maven comes shipped with a default main repository, but I've found that in many cases this repository is not up to date. (...)

Even if the idea behind the concept of a central repo is noble, you can't objectively expect it to contain all jars in the world. One of the most obvious reason is that uploading artifacts to the Central Repository just takes time and resources are not infinite. And because companies like RedHat JBoss or SpringSource or Sun or even me need flexibility, reactivity (in one word, control), it's not surprising that they use their own repository. And, actually, I'm pretty happy that they expose them. But indeed, projects need to document where to find their artifacts if they are not available in central. Just in case, you may find this How to find dependencies on public Maven repositories? helpful. In a corporate environment, the best way to handle this would be to setup a centralized (corporate) proxying repository. See this page for such solutions.

Closely related to number 2 is ensuring you have the correct version of an artifact. (...)

Sorry but you need a bit to know what you're are doing. A project can't guess for you what JSTL version you are going to use. Then, regarding the various versions of artifacts, the naming convention used by projects has nothing to do with maven, this is a project/vendor choice (except for SNAPSHOT that maven handles specially). FWIW, common used schemes include: M1 = Milestone 1, RC1 = Release Candidate 1, GA = General Availability (final release), CR = Customer Release (often a bug-fix release). You may also see alpha, beta. This really depends on the project lifecycle and convention (nothing really unusual here though).

Finally, the issue of the type a dependency. I probably just don't understand this well enough, but many repo artifacts are of type "pom" not "jar". (...)

I think that you're indeed lacking of experience. You seem to be fighting with dependencies while things just go smoothly for me :) Maybe using a repository search engine will help.

Pascal Thivent
A: 

You can also exclude some transitive dependencies, like the following example:

<dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.15</version>
        <exclusions>
            <exclusion>
                <groupId>javax.mail</groupId>
                <artifactId>mail</artifactId>
            </exclusion>
            <exclusion>
                <groupId>javax.jms</groupId>
                <artifactId>jms</artifactId>
            </exclusion>
            <exclusion>
                <groupId>com.sun.jdmk</groupId>
                <artifactId>jmxtools</artifactId>
            </exclusion>
            <exclusion>
                <groupId>com.sun.jmx</groupId>
                <artifactId>jmxri</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

I don't remember the details, but apparently some other dependencies were being discovered when we wanted to use log4j, and we had no interest (or need) in them in our case, so my cow orker just said "no thanks to these" and it works.

M1EK