views:

1321

answers:

3

Colleagues have been touting the wonders of maven and its magical dependency stuff but I'm finding that it fails at what I would consider the obvious use.

Suppose I have a root folder with a master POM.

Then underneath I have some projects, call them A and B

B requires A and so the POM in the B folder has the appropriate dependency entry in it

Now, back in the root folder, in a profile, I specify that I want to build B.

When I perform the usual mvn clean install, I get a failure because A was not built.

My friends tell me I have to specify both A and B in that main profile in the root.

But isn't the whole point of dependency management that maven sees B, goes to the B POM file where it sees the dependency on A and so it should go build A automatically.

+5  A: 

With the master POM:

<?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"&gt;
    <modelVersion>4.0.0</modelVersion>
    <groupId>scratch</groupId>
    <artifactId>scratch</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>mod1</module>
        <module>mod2</module>
    </modules>
</project>

And the module POMs:

<?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"&gt;
    <parent>
        <artifactId>scratch</artifactId>
        <groupId>scratch</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <groupId>scratch</groupId>
    <artifactId>mod1</artifactId>
    <version>1.0-SNAPSHOT</version>
</project>

<?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"&gt;
    <parent>
        <artifactId>scratch</artifactId>
        <groupId>scratch</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <groupId>scratch</groupId>
    <artifactId>mod2</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>scratch</groupId>
            <artifactId>mod1</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
</project>

I can issue mvn package in the root directory after clearing out my local repository and end up with all the modules built. (Into empty-ish JARs, but built.)

Maven seems to look for dependencies either in the repository, or in the build in progress. It will not automatically traverse your project structure when you're only building a single module, because it's not required that you even have the parent project on your computer, much less one directory above the current module. (The parent-child relationship isn't even bijective.)

A reason why this is so might be because a directory layout where the location of modules would be predictable is in no way mandatory. It's even somewhat common and acceptable that the layout for the above example be like this:

projects
|
+--scratch
|  |
|  +--scratch-parent
|  |  |
|  |  +--pom.xml [The POM of scratch:scratch:1.0-SNAPSHOT]
|  |
|  +--nipple
|  |  |
|  |  +--pom.xml [The POM of scratch:mod1:1.0-SNAPSHOT]
|  |
|  +--cabbage
|  |  |
|  |  +--pom.xml [The POM of scratch:mod2:1.0-SNAPSHOT]

In this case, the <modules> section of the parent POM would be:

<modules>
    <module>../nipple</module>
    <module>../cabbage</module>
</modules>

Notice that there is nothing saying which artifact ID is in which module. It just serves to tell Maven that these are filesystem locations where to search for other artifacts related to this build.

Sii
Clearly it's not required. BUT since it did start running in a parent folder AND it has a reference to a module that it can find in a child folder AND it knows all the children underneath it, it should be able to figure out for itself that if there's a dependency on another module, then just MAYBE it should go look for that one.At least this should be an option -- it seems like a very reasonable thing to want to be able to do. Otherwise we have this incredibly sophisticated tool that can do all sorts of complicated stuff but can't handle the basics!
David
I never needed to build only one module of a project + its dependencies as opposed to just building the whole thing - obviously "the basics" and "a reasonable thing to want" is subjective. If you're asking how to make your project build, you got that. If you want to know the rationale behind it, I suggest contacting the Maven team. If you want it changed, I suggest a bug report. If you just want to bash Maven...
Sii
I'm not trying to bash Maven --- I thought I was asking a reasonable question.Transitive dependency means that dependencies should not have to be defined globally.Even if you're building an entire project, I would still argue that Maven SHOULD be able to figure out the module dependencies by looking at the individual POMs.I can use it the way it is...I'm not asking for help --- I'm simply (honestly) astonished that it doesn't have such an ability and in fact the reason I posted here was with the hope that perhaps there was an option I didn't know about that would let me do this.
David
It's not dependencies that are defined globally. Just where else besides the repositories should Maven look for them when doing a build. If you had first installed A into your local repository, and then tried to build B, it would work. It's just that when you want Maven to resolve a dependency tree in a large project or rebuild a module's dependencies with it, you have to build them all in the same cycle.
Sii
Thanks --- I realize how Maven does behave. My comment is really about how Maven OUGHT to behave. A mechanism that tells Maven that it should in fact look in child folders for projects would (it seems to be) be extremely valuable.
David
A: 

A reason I can think of that your desired behaviour hasn't been implemented is as follows:

Suppose I'm working on both projects A and B. Currently A is broken. If dependency resolution happened as you would like, I would never be able to build B until A was fixed. So I either have to roll back my changes to A, or focus on fixing A first. Either way possibly not what I want to focus on right now.

Generally B wants to work with the "last good" version of A, rather than the latest. Using the dependencies from the repository means they at least compiled ok (and hopefully the unit tests were run too).

Rich Seller
+4  A: 

Take a look at the Maven reactor plugin, in particular reactor:make, which builds a module and all of the modules which it depends on.

deterb