views:

91

answers:

3

Example scenario: I have 2 projects, "common-project" and "application-project". The application-project depends on the API provided by common-project. There are also 3rd party jars (example guava) used by both projects.

I am trying convert to using maven and m2eclipse, but am unclear on the best approach. Currently, my maven-free setup has the 3rd party jars added as libraries on common-project, and marked as "exported". This way they are inherited by application-project, and I don't have to explicitly add them as libraries on application project. Both projects are under active development, so I would prefer not to have to build a jar of common-project first, then "install" that to my local repository before I can use the new features in application-project.

What is the recommended approach for this type of project layout? I see the following thread touches roughly on the topic: http://stackoverflow.com/questions/2539854

Thanks

A: 

Express the dependencies that each project has in the <dependencies> element of the POM.

The m2eclipse plugin will then automatically pick these up, from the pom.xml, and add them as library references to the build path within Eclipse.

If application-project depends on common-project, then it will inherit it's dependencies as well - it will not be necessary to list the common dependencies between the two a second time in the pom.xml of application-project.

matt b
A: 

Assuming you already have maven installed in your computer, then download the m2eclipse pluging install it and restart eclipse.

Remember the goal of a maven build is to produce and artifact that can be distributed and reused, it's OK if you don't want to make a mvn install before having a somewhat stable version of you "common-project" API, although there is nothing wrong in doing it during development.

For your case you can do one of the following:

  1. If common-project API is absolutely necessary and will more often than not only be used in the confines of the application-project then build your project as a multi-module project and declare common-project to be a module of your application project. Here is an example of how to do this.
  2. If otherwise common-project will be more often than not a shared artifact, then build each project independently having declared the dependencies of both in their pom.xml files eclipse should be able to figure out the dependency between the two.
  3. You could develop a partial implementation of common-project first, package it, and then declaring as a dependency in application-project with the <scope>system<scope> specifying where in the file system it is located, this will tell maven that the dependency is always present and it would not look it up in any repository; although doing a mvn install will be more elegant than this you're trying to avoid that.

Regards.

StudiousJoseph
Thanks - I guess I should just go with making common-project a shared artifact, and see how it works out. It looks like I can still set up project dependencies with eclipse so that refactoring can still be applied across multiple projects.
MavenN00b
I'm totally against using `system` scoped dependency, this is a very bad practice that shouldn't be encouraged, people are just abusing it.
Pascal Thivent
+1  A: 

Example scenario: I have 2 projects, "common-project" and "application-project". The application-project depends on the API provided by common-project. There are also 3rd party jars (example guava) used by both projects.

I would create 3 maven projects: a parent aggregating module, a common-project module and an application-project module depending on common-project and declare guava as dependency in the parent module (so that child project will inherit it). Something like this:

$ tree Q3337426
Q3337426
├── application-project
│   ├── pom.xml
│   └── src
│       ├── main
│           └── ...
│       └── test
│           └── ...
├── common-project
│   ├── pom.xml
│   └── src
│       ├── main
│           └── ...
│       └── test
│           └── ...
└── pom.xml

Where the parent pom.xml looks like this:

<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/maven-v4_0_0.xsd"&gt;
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.stackoverflow.Q3337426</groupId>
  <artifactId>Q3337426</artifactId>
  <packaging>pom</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>Q3337426 - Root</name>
  <url>http://maven.apache.org&lt;/url&gt;
  <dependencies>
    <dependency>
      <groupId>com.google.guava</groupId>
      <artifactId>guava</artifactId>
      <version>r05</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
  <modules>
    <module>common-project</module>
    <module>application-project</module>
  </modules>
</project>

The pom.xml for the common-project:

<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>
  <parent>
    <artifactId>Q3337426</artifactId>
    <groupId>com.stackoverflow.Q3337426</groupId>
    <version>1.0-SNAPSHOT</version>
  </parent>
  <artifactId>common-project</artifactId>
  <name>Q3337426 - Common Project</name>
  <dependencies/>
</project>

The pom.xml for the application-project:

<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>
  <parent>
    <artifactId>Q3337426</artifactId>
    <groupId>com.stackoverflow.Q3337426</groupId>
    <version>1.0-SNAPSHOT</version>
  </parent>
  <artifactId>application-project</artifactId>
  <name>Q3337426 - Application Project</name>
  <dependencies>
    <dependency>
      <groupId>${project.groupId}</groupId>
      <artifactId>common-project</artifactId>
      <version>${project.version}</version>
    </dependency>
  </dependencies>
</project>

This is the Maven way to organize such a project and will allow to trigger a reactor build from the root project to build everything.

(...) Both projects are under active development, so I would prefer not to have to build a jar of common-project first, then "install" that to my local repository before I can use the new features in application-project.

The m2eclipse plugin can Resolve dependencies from Workspace projects (this is actually the default behavior). So if you import both application-project and common-project, the former would be configured to depend on the sources of common-project (instead of depending on the jar). Changes made to common-project will be immediately visible when using this setup.

This should solve your concern inside the IDE. Outside the IDE, run a reactor build on the top project.

Pascal Thivent
Thanks for the comprehensive response, I'll certainly be looking into this.
MavenN00b
@MavenN00b: You're welcome. Should be pretty easy to adapt to your real project. Feel free to ask if you need a clarification.
Pascal Thivent