Maven doesn’t suck, your POM does
Maven bashing is an all-time favorite: there are plenty of articles telling how Maven downloads the whole Internet, or how POMs are bloated and so on.
While I agree that Maven could be perfected, I’m also aware that some (if not most) of its shortcomings are not intrinsic but are caused by (very) bad configuration. Worse, even if used correctly in your projects, problems sometimes come from third-party dependencies! You do not believe me? Well, two examples follow, from standard libraries.
Coming from the classic logging framework, this may seem a surprise but log4j POM is a mess. Just look at its dependencies section:
<dependencies> <dependency> <groupId>javax.mail</groupId> <artifactId>mail</artifactId> <version>1.4</version> </dependency> <dependency> <groupId>javax.jms</groupId> <artifactId>jms</artifactId> <version>1.1</version> </dependency> ... </dependencies>
Interestingly enough, Log4J depends on the Java Mail and JMS API! If you are using your application in an application server, you may be in for a rude surprise as conflicts may arise between your dependencies and the libraries available on the server.
Moreover, while some users may have the need of mail or JMS appenders, this is not the case for all of us. As such, there’s clearly a lack of appropriate modularization in the design of the library. Luckily, the above POM is an excerpt of version 1.2.15. Version 1.2.16 uses the optional tag for those libraries (which breaks transitivity): it addresses our application server use-case but is still a problem for those needing the dependencies as they have to add the dependency manually. See here for a thought or two on optional dependencies.
If we need version 1.2.15, there are basically two solutions.
- Clean but cumbersome: we have to manually exclude JMS and Mail from each POM using Log4J. Who said software development was fun?
- Gruesome but effective: if we have a Maven enterprise repository, we correct the POM (i.e. we add optional tags) on the repository.
The Log4J example was straightforward: just the side-effects of bad modularization. Jasper’s POM has another twist, just look at a typical dependency:
<dependency> <groupId>com.lowagie</groupId> <artifactId>itext</artifactId> <version>[1.02b,)</version> <scope>compile</scope> </dependency>
The version part means the dependency’s version should be between 1.02b included and the latest version. This obviously has two drawbacks:
- From an architectural point of view, how can the POM provider guarantee there won’t be an API break with the latest version?
- From a Maven POV, it means Maven will try to download the latest version. In order to do that, it will try to contact repo1… You’re beginning to see the problem? If you’re behing a corporate proxy that isolates you from the Internet, you’re toast.
The POM excerpt comes from version 2.0.4. Starting from version 2.0.5, Jasper’s designers used only single version dependencies.
If you’re stuck with older versions, the only solution here is to replace the POM with a manually crafted one that do not use unboundedversion dependencies on your enterprise repository.
Despite the constant noise on the Internet, Maven is a wonderful tool. Yet, even if I take the utmost care to design my POM, some external dependencies make my life harder. It would be better to stop losing time complaining about the tool and invest this time helping the developers of those dependencies to provide better POMs.