Maven: Split Your Project Into Sub-Projects

http://maven.apache.org/plugins/maven-eclipse-plugin/reactor.html

Multiproject Maven Projects

Multiple Maven (and Eclipse) projects can be combined together to form a larger project. Maven expects there to be a separate Maven project to represent the overall whole, in addition to the projects that make up the individual modules. The structure of the parent project and its pom.xml can be fairly simple: just a pom.xml that specifies the modules that make up the project, and optionally a src/sitedirectory for the overall project’s Maven site.

The structure of such a project would look like this:

+-- workspace/
	+-- myproject/
	|	+-- pom.xml
	|	+-- .project
	|	+-- src/
	|		+-- site/
	|			...
	+-- subproject-1/
	|	+-- pom.xml
	|	+-- src/
	|	|	+-- main/
	|	|	|	+-- java/
	|	|	|	|	...
	|	|	|	+-- resources
	|	|	|		...
	|	|	+-- test/
	|	|		+-- java/
	|	|			...
	|	+-- .project
	|	+-- .classpath
	+-- subproject-2/
		+-- pom.xml
		+-- src/
		|	...
		+-- .project
		+-- .classpath

…where “myproject” is the overall (parent) project that you’re working on, which is made up of modules subproject-1 and subproject-2.

The pom.xml for myproject would look 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">

	<modelVersion>4.0.0</modelVersion>
	<groupId>ca.intelliware</groupId>
	<artifactId>myproject</artifactId>
	<packaging>pom</packaging>

	<version>1.0-SNAPSHOT</version>

	<name>My Project</name>

	<modules>
		<module>../subproject-1</module>
		<module>../subproject-2</module>
	</modules>

	...
</project>

…which makes myproject your “one stop shopping” location for running mvn goals such as install or release or eclipse:eclipse. Maven will descend into each of the projects that you specified in your module section, and run that goal for each subproject.

In each of the subprojects, the pom.xml needs to contain a parent directive that refers back to the parent pom.xml for the larger project. So subproject-1‘s pom.xml would look something like this:

<?xml version="1.0"?>
<project>
  <parent>
    <artifactId>myproject</artifactId>
    <groupId>ca.intelliware</groupId>
    <version>1.0-SNAPSHOT</version>
  </parent>

  <modelVersion>4.0.0</modelVersion>

  <groupId>ca.intelliware</groupId>
  <artifactId>subproject-1</artifactId>
  <version>1.0-SNAPSHOT</version>

  ...

</project>

Frequently, one subproject will depend on another. That’s as simple as adding a dependency to the project’s pom.xml that refers to a snapshot (not a release version) of the other project. So if subproject-2 consumes subproject-1as a dependency, its pom will look something like this:

<?xml version="1.0"?>
<project>
  <parent>
    <artifactId>myproject</artifactId>
    <groupId>ca.intelliware</groupId>
    <version>1.0-SNAPSHOT</version>
  </parent>

  <modelVersion>4.0.0</modelVersion>

  <groupId>ca.intelliware</groupId>
  <artifactId>subproject-2</artifactId>
  <version>1.0-SNAPSHOT</version>

  <dependencies>
	<dependency>
		<groupId>ca.intelliware</groupId>
		<artifactId>subproject-1</artifactId>
		<version>1.0-SNAPSHOT</version>
	</dependency>
  </dependencies>

  ...

</project>

If you run the eclipse:eclipse goal out of the parent project’s directory, the eclipse:eclipsegoal is smart enough to understand that the Eclipse project for subproject-2 should reference the Eclipse project for subproject-1 as a project dependency in its Java build path, and that’s what you’ll get in the resulting Eclipse projects. Eclipse will treat the two projects as one big happy namespace, as usual, and you’ll be able to do refactorings across the boundaries of the two projects, and so forth.

You can also draw a sharp line between the two subprojects, and force them into a more formal producer/consumer relationship with defined interfaces by depending on a release version of the other subproject instead of a snapshot. In that case, the Eclipse project that gets generated by the eclipse:eclipse will simply refer to the released version of the JAR in your M2_REPO repository, and any changes you might make to subproject-1 if you were to open that project in your workspace wouldn’t be reflected in the build of subproject-2.

Creating a New Multiproject Project

  1. Go to your Eclipse workspace in the Command Prompt (or Cygwin shell), and run
    mvn archetype:create -DartifactId=myNewProject -DgroupId=ca.intelliware
  2. Go into your new myNewProject directory and edit your pom.xml to have a packaging of pom
  3. In your new myNewProjectdirectory, for each of the sub-projects that you have run the following:
    mvn archetype:create -DartifactId=myNewSubProject-i -DgroupId=ca.intelliware
  4. Move your sub-project directories on the same level as your parent myNewProjectproject (i.e. move them up directly into your Eclipse workspace directory).
  5. Edit the pom.xml of your myNewProject project to reference sub-project modules on the same level, i.e. add ../like this:
    <modules>
    		<module>../myNewSubProject-1</module>
    		<module>../myNewSubProject-2</module>
    </modules>

    Note that your sub-project modules should have already been added to the parent’s pom.xml when you ran the archetype to create the sub-projects.

  6. In the myNewProjectdirectory, run
    mvn -DdownloadSources=true eclipse:eclipse

    .

  7. Open up Eclipse, right click on the Package Explorer, and do “Import/Existing Projects Into Workspace” for your subprojects. You don’t need to import your parent “myNewProject” project into Eclipse.
  8. All your maven goals for all of your sub-projects need to be run only once in the directory where myNewProject’s pom.xml is.
  9. Now you’re ready to start crunching code in Eclipse in your sub-projects.

Splitting an Existing Project

  1. We’re assuming that you’re starting with a Maven project named foobarin your Eclipse workspace, and that you’ve now realized that it needs to be split into two (or more, but for the sake of this example, we’ll assume two) smaller projects.
  2. Pick names for your smaller projects. We’ll call them foo and bar, and we’ll refer to the whole thing as foobar.
  3. Go to your Eclipse workspace, and rename your existing project to one of the names that you picked for your subprojects, preferably the top level one if there’s a chain of dependencies. In this case, let’s assume that project foo is going to depend on project bar, so we’ll rename foobar to foo.
  4. Also in the workspace, run
    mvn archetype:create -DartifactId=foobar -DgroupId=ca.intelliware

    in the command line.

  5. Edit foobar/pom.xml, and change the packaging to pom.
  6. Descend into the foobardirectory, and run
    mvn archetype:create -DartifactId=bar -DgroupId=ca.intelliware

    Maven will create this new project as a sub-project of foobar.

  7. Move the bar directory up into the workspace, where it will be a sibling of foo and foobar.
  8. Copy the parent stanza from bar/pom.xml into foo/pom.xml, and edit foo/pom.xml to change its artifactId from foobar to foo.
  9. Edit foobar/pom.xml, and change the modulessection to the following:
    <modules>
        <module>../foo</module>
        <module>../bar</module>
    </modules>
  10. Move the code that you wanted to split from foo to bar.
  11. Run
    mvn eclipse:eclipse

    in the foobardirectory.

  12. Share the resulting directories to your version control system.
  13. Share and enjoy!

It's only fair to share...
Share on FacebookGoogle+Tweet about this on TwitterShare on LinkedIn

Leave a Reply