3

Env: Maven 2.2.1 I have two java projects under svn (projectA, projectB). My maven structure is as follows..

For projectA 
pom.xml (contains ProjectA parent pom definitions)

   module moduleA
   module moduleB


For projectB 
pom.xml (contains ProjectB parent pom definitions)

   module moduleC
   module moduleD

projectA/pom.xml and projectB/pom.xml contain common definitions like junit, selenium, compiler, eclipse plug-ins which are common to both projects. (e.g. given below)

    <dependency>
        <groupId>commons-lang</groupId>
        <artifactId>commons-lang</artifactId>
        <version>2.4</version>
        <type>jar</type>
        <scope>compile</scope>
    </dependency>

    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.7</version>
        <scope>test</scope>
    </dependency

How should I create / organize a organization specific project pom which includes such common definitions, so that individual projects don't have to re-create / maintain one. Can someone provide some snippets or projects which have already done this before?

EDIT1:

company/pom.xml

<modelVersion>4.0.0</modelVersion>

<groupId>com.mycompany</groupId>
<artifactId>company</artifactId>
<packaging>pom</packaging>

<name>parent</name>
<version>1.0.0</version>

<build>
    <defaultGoal>install</defaultGoal>
</build>

<dependencies>
    <dependency>
        <groupId>commons-lang</groupId>
        <artifactId>commons-lang</artifactId>
        <version>2.4</version>
        <type>jar</type>
        <scope>compile</scope>
    </dependency>

    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>servlet-api</artifactId>
        <version>2.5</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

projectA/pom.xml

<modelVersion>4.0.0</modelVersion>

<parent>
    <groupId>com.mycompany</groupId>
    <artifactId>company</artifactId>
    <version>1.0.0</version>
</parent>

<groupId>com.mycompany</groupId>
<artifactId>projectA</artifactId>
<packaging>pom</packaging>

<name>projectA</name>
<version>1.0.0</version>

<modules>
    <module>moduleA</module>

<build>
    <defaultGoal>install</defaultGoal>
</build>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

projectA/moduleA/pom.xml

<modelVersion>4.0.0</modelVersion>

<parent>
    <groupId>com.mycompany</groupId>
    <artifactId>projectA</artifactId>
    <version>1.0.0</version>
    <relativePath>../pom.xml</relativePath>
</parent>

<groupId>com.mycompany</groupId>
<artifactId>moduleA</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>

<name>moduleA</name>

<build>
    <finalName>moduleA</finalName>
    <defaultGoal>install</defaultGoal>
</build>

<dependencies>
    <dependency>
        <groupId>commons-lang</groupId>
        <artifactId>commons-lang</artifactId>
    </dependency>

    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>servlet-api</artifactId>
    </dependency>
</dependencies>

Throws the following error:

Project ID: com.mycompany:moduleA
POM Location: c:\temp\maven\projectA\moduleA\pom.xml
Validation Messages:

    [0]  'dependencies.dependency.version' is missing for commons-lang:comm
ons-lang:jar
    [1]  'dependencies.dependency.version' is missing for javax.servlet:ser
vlet-api:jar
Joe
  • 14,513
  • 28
  • 82
  • 144

3 Answers3

7

I would seriously reconsider adding dependencies into a "super" POM, this unnecessarily couples the projects (but may hint that if the projects aren't disparate then they should be merged anyway). I think the last comment by @lexicore is poignant too, to expand on the OOP analogy it also feels like "mixing levels of abstraction".

Alex Gitelman provides the correct answer, you need to use dependencyManagement as shown here Dependency Scope

Maven3 is supposed to be supporting POM fragments see How to use Maven 3 mixins? which I've long been waiting for.

We have an organisation Über POM but this just contains:

<organization>
    <name>...</name>
    <url>...</url>
</organization>

<developers>
    <developer>
        <id>...<id>
        <name>...</name>
        <email>...</email>
        <roles>
            <role>...</role>
        </roles>
    </developer>

<distributionManagement>
    ...
</distributionManagement>

<repositories>
    <!-- your proxy repo here -->
</repositories>

These are things that change very rarely (if we change our repository/distribution-management then all projects must change, if a developer leaves or joins we can update the project POMs at any time convenient).

Dependencies belong specifically to the module under consideration, just because two independent project happen to share dependencies now doesn't mean they always will. I completely understand the annoyance of having to copy 'n' paste reams of XML for each project (compiler plugin, reporting plugins, junit etc), but differing levels of activity in each project will surely mean they diverge at some point.

WRT cascade builds in Continuous Integration, if project A demands a change in the super dependencies POM, then all you other projects will be forced to rebuild - maybe fine if you've only 2 projects but even then did you checkout and build both before committing the change?

Community
  • 1
  • 1
earcam
  • 6,662
  • 4
  • 37
  • 57
4

If it's only dependencies that you need to reuse, create another project with packaging pom and specify dependencies there. Let's call it OrgDependencies Then include it as dependency in your projectA and projectB. It will transitively pull all dependencies from OrgDependencies project.


In your example, in projectA, instead of

<parent>
    <groupId>com.mycompany</groupId>
    <artifactId>company</artifactId>
    <version>1.0.0</version>
</parent>

Try putting

<dependencies>
  <dependency>
    <groupId>com.mycompany</groupId>
    <artifactId>company</artifactId>
    <version>1.0.0</version>
  </dependency>
</dependencies>

And remove dependencies to commons-lang etc from modules.


Update.

While my previous solution with transitive dependencies should work, actually what you need is <dependencyManagement> section in your company wide pom.xml

That's where you define versions.

Note: Anything in dependencyManagement section is not really a dependency but just a descriptor that allows to specify version and exclude transitive dependencies (if necessary) in case normal dependencies section specifies that dependency. So you can put as many items in dependencyManagement as you want, it will not make all descendants dependent on them.

I tested it and it works:

<?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">

    <modelVersion>4.0.0</modelVersion>

    <groupId>com.mycompany</groupId>
    <artifactId>company</artifactId>
    <packaging>pom</packaging>

    <name>parent</name>
    <version>1.0.0</version>

    <build>
        <defaultGoal>install</defaultGoal>
    </build>

    <dependencyManagement>
        <dependencies>
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.4</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
            <scope>provided</scope>
        </dependency>
        </dependencies>
    </dependencyManagement>
</project>
Alex Gitelman
  • 24,429
  • 7
  • 52
  • 49
  • I tried your suggestion, but it's unable to pull the transitive dependencies in my submodules – Joe Jun 10 '11 at 06:49
  • Can you provide specifics? How did you set up your parent project? How did you refer to it? What is the error? This approach definitely works for me. – Alex Gitelman Jun 10 '11 at 06:55
  • I have done exactly as mentioned in the sample below, the only difference being the company wide pom contains all dependencies/versions. Hence the sub module is unable to resolve. If the dependencies/versions are present in the project pom, then the submodule is able to resolve the dependencies/versions – Joe Jun 10 '11 at 07:31
  • [1] 'dependencies.dependency.version' is missing for commons-lang:commons-lang:jar [2] 'dependencies.dependency.version' is missing for javax.servlet:servlet-api:jar – Joe Jun 10 '11 at 07:32
  • It may be a problem due to different scopes. Jusy for testing, can you set all scopes to compile? Other thing, do you actually specify all dependencies in your projects but just skip versions? O don't think that will work. – Alex Gitelman Jun 10 '11 at 07:42
  • @Alex - I don't think its a scope issue, just verified it. – Joe Jun 10 '11 at 07:51
  • 1
    Thanks for adding code. modules should not explicitly specify dependencies. Instead either them or projectA/ projectB should include dependency to parent. If you want to have separate dependencies and just specify versions from parent pom, then its not right approach. In this case, just try to refer to parent pom via `parent` tag. – Alex Gitelman Jun 10 '11 at 08:17
  • @Alex - A little confused here. I added the parent tag in moduleA/pom.xml so that developers can build from that directory. Also, I am referring to the company wide pom in projectA/pom.xml via the parent tag. What corrections should I make to run this. – Joe Jun 10 '11 at 08:40
  • 1
    I edited answer to add some explanation. Although I would expect your solution with parent to work as well. I will try some experiments if I have time later. – Alex Gitelman Jun 10 '11 at 15:23
  • @Alex - I did try your suggestion sometime back and it didn't help. Appreciate if you can help here to resolve this issue. – Joe Jun 10 '11 at 16:59
  • @Alex - I need those dependencies in order to compile moduleA, I don't think I will be able to remove them (since it could be a ejb or a war module). Note: If I remove the dependencies it works, but I need those dependencies. – Joe Jun 10 '11 at 17:16
  • I don't suggest removing them completely. They should get pulled transitively from parent pom dependency. Although, I remember we had some problems with ear. Have you confirmed that they don't make it to war/ear? – Alex Gitelman Jun 10 '11 at 17:23
  • Removing dependencies on moduleA, doesn't resolve compilation issues as its looking for the same set of jars for compiling the code. – Joe Jun 11 '11 at 03:38
  • @Joe Sorry I've been pretty caught up at work. There is only that much I can do using comments here, though. Especially without having entire pom files. – Alex Gitelman Jun 14 '11 at 06:09
  • @Alex - The pom files attached to the question, actually reproduces this issue. Let me know, if you are not able to reproduce with what is available here. – Joe Jun 14 '11 at 11:42
  • @Joe I admit being total fool. We just missed the fact that those version specifications in parent poms, require `` section. I tested your set up and it seems to work (not sure how war plugin will work though). I updated the answer. – Alex Gitelman Jun 15 '11 at 05:27
3

In OS projects I am normally using 3+ levels of POMs:

  • "Company-wide POM" contains dev-wide definitions like distribution management, individual plugin versions etc. Very stable, normally has one-number version. Example: Sonatype OSS Parent.
  • "Project POM" contains project-wide definitions: Java compiler version, dependency management etc. Parent is company-wide POM. Example :JAXB2 Basics Project. Version is updated with each release.
  • "Module POMs" on different levels. List individual dependencies (versions of dependencies are inherited from the project POM), add "special" build steps. Example: JAXB Basics.

I saw a similar pattern an other OS projects (like Apache's) as well.

A few more comments:

  • You may also have the "department POM" or "product POM" depending on the company size and product organization.
  • Think of POM inheritance pretty much as of OOP inheritance. What would you put into which abstract class so that class hierarchy is stable but dynamic? For instance, it would not make sense to define versions of dependencies in the company-wide POM since versions change too often. On the contrary, defining distribution management in earch of the projects would hurt the DRY principle.
lexicore
  • 42,748
  • 17
  • 132
  • 221
  • I have done exactly as mentioned in the sample above, the only difference being the company wide pom contains all dependencies/versions. Hence the sub module is unable to resolve. If the dependencies/versions are present in the project pom, then the submodule is able to resolve the dependencies/versions – Joe Jun 10 '11 at 07:28