OK... Who put the JUnit JAR in my WAR?

Paul Brown @ 2007-03-07T02:26:15Z

My odyssey with Maven continues. This entry is spurred by having a WAR built with Maven come out to be three times the size of the one built with the original Ant build. JUnit, JMock, a couple of different Log4J's, and other assorted goodies. With multiple modules and liberal use of open source components, the question is not whether someone did but who peed in which POM?

Open source reminds me of college. I had the opportunity to enjoy some eclectic people during my education at Reed and Berkeley. Rent a room and then sublet the closet? That's cool. Eat what others would otherwise throw away in the dining commons? That's cool. (Off topic, at least one former "scrounger" has done just fine...) These sort of situations came with their own etiquette, e.g., tell a "scrounger" if you have a cold when you drop off your tray and leave items intact and relatively unmolested. The bohemian analogy cuts both ways with open source — you can probably find whatever you are looking for, but it may not be in quite the state that you'd like.

Some shell scripting (find, grep, xargs, and friends) identified commons-httpclient as the likely culprit, and sure enough, it's there plain as day:

<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>3.8.1</version>
</dependency>

There should be a <scope>test</scope>, but there isn't. Since he helps steward the commons, I pinged Henri about it, and it looks like the issue was already fixed for versions 3.1 and on. This was only part of the battle, however, because commons-httpclient wasn't an explicit dependency; it was only getting included as a transitive dependency of some other dependency of one of the modules that the web application used, and the module hierarchy was already four levels deep. Surely someone else has already experienced issues with dependencies of unknown provenance and come up with a way to navigate the graph, and it turns out that there are (at least) two solutions.

First up, for playing Heracles to my Odysseus or Anchises to my Aeneas or Virgil to my Dante or Laurel to my Hardy or whatever in JAR hell, Henri gets a hat-tip for pointing me at the pomtools plugin, which provides an interactive interface for navigating the graph of dependencies and can alter and serialize the underlying model of the project to fix version conflicts. I didn't end up trying it, but I will, since I have a soft spot for anything with a terminal interface.

Instead, since I also have a soft spot for GraphViz, I used the depgraph plugin from the EL4J project, which I found via Philipp Oser's blog. In my case, the plugin produced the following graph:

The graph showed commons-httpclient referenced by a variety of XFire components, and some exclusions got me out of JAR purgatory for the moment. (I ate a couple of whole pomegranates down there, so I'm sure I'll be headed back sometime soon...) This isn't just a Jakarta Commons issue. XFire has a little of the same kind of POM-rot as of 1.2.3, but that will disappear in the forthcoming 1.2.5. For those keeping score at home, AXIS2 has some (xmlunit should be <scope>'d to test), too. This makes me wish for a Maven "lint" that would flag common errors like test libraries listed as runtime dependencies or dependencies not referenced from runtime source code.

Getting the depgraph plugin wired-up was straightforward. I just added a plugin repository to the master POM:

<pluginRepositories>
  <pluginRepository>
    <id>elca-services</id>
    <url>http://el4.elca-services.ch/el4j/maven2repository</url>
    <releases>
      <enabled>true</enabled>
    </releases>
  </pluginRepository>
</pluginRepositories>

Then the plugin to the build:

<build>
[...]
  <plugins>
    [...]
    <plugin>
      <groupId>ch.elca.el4j.maven.plugins</groupId>
      <artifactId>maven-depgraph-plugin</artifactId>
      <configuration>
        <outDir>target/site/images</outDir>
        <outFile>${pom.artifactId}.png</outFile>
      </configuration>
    </plugin>
  </plugins>
</build>

And then it's just a mvn depgraph:depgraph to get a view of the dependency graph. The real lesson here is to aggressively scope your dependencies as a service to the community.

(comment bubbles) 5 comments

Maven and Rakes in the Grass

Paul Brown @ 2007-02-26T00:00:00Z

When you first experience Maven, it's like the cinematic cliché of two lovers running across a grassy field to embrace: It takes care of getting the right JARs for you, keeps test and build dependencies separate, and generates configuration artifacts for your favorite IDE, too. Even though it's XML, it's still a sweet five-minute user experience, but then you start stepping on the rakes in the grass:

"Hmmm. Doesn't look like Emma is supported by Maven2, so I'll give Cobertura a shot." THWAP! The current version of the plugin is broken, but downgrading to an earlier version appears to work.

"Looks like TestNG support only extends to version 4.7, but maybe my tests written against 5.5 will still work." THWAP! It turns out that up to date support for TestNG is a bit of a can of worms. (I would have tried the 2.8-SNAPSHOT version, but the pom was broken.)

"Oh well. I can switch to JUnit4 and do without data providers, make @BeforeClass methods static, and replace dependency-driven order of execution by some hand-coded magic." THWAP! The documentation doesn't explicitly state that the current version of the Surefire plugin is for JUnit 3.8 only, but it is. Adding the Apache plugin snapshot repository and using the 2.3-SNAPSHOT version of the plugin gets things working. (Of course, then it also turns out that IDEA 6 doesn't support JUnit 4.2.)

This is no worse than dealing with dependencies and working directories in Ant, so I'm happy enough with Maven in the relatively green-field environment that I'm working in. I can see where trying to bend an existing project, especially a large one, to Maven could quickly become a fool's errand.

I have to admit that I looked closely at Maven in its version 1 incarnation, but it flunked the five minute test. (Among other things, I was never able to grok how the "reactor" worked for multi-module builds.) Maven 2, thanks to the Apache site and the book and examples from Mergere, gets over that hump. (FiveSight had a home-grown multi-module build system built on top of Ant, but it didn't do an especially good job of rolling-up reporting or of managing conflicts in transitive dependencies (lib A version C requires lib B version D, but lib E requires lib B version F).)

I do like where Matthieu is headed with raven or Russel Winder is headed with gant, but I'd really like the two together: non-XML syntax, dependency management, fully-stocked and up-to-date repositories, well-supported by continuous integration systems, and works with everything that Ant works with. Maybe gant plus the Maven2 Ant tasks or Ivy is the most silver-ish bullet for the time being, but seeing as I don't need to shoot any werewolves, Maven fits the bill for the moment.

(comment bubbles) 3 comments