2

Context:

The question is regarding a multi-module (maven, not Java 9 modules) Java project using maven for building it, where one module depends on the jar of another module.

Overview of the modules and some context:

  • A: a library compiled to a jar.
  • B: a client application, that depends on jar of A; compiled to an executable jar.
  • C: a server application, neither depending on A nor B; compiled to an executable jar.
  • I can only use Java 8 and thus no Java 9 modules.
  • The IDE used is IntelliJ IDEA Ultimate.

What works:

  • Building the modules to three separate jars (executable in case of B and C) using mvn clean package.
  • Importing the packages from module A into the classes of module B (not what I want).
  • Adding a dependency to module A into the pom.xml of B (I don't know what effect this has...).

What I would like to achieve:

  • I would like to add a dependency to the jar built from module A to the pom.xml of module B.
  • I would like to import public classes and interfaces from the jar of module A in the classes of module B (by adding it as a dependency in the pom.xml and without copying the jar manually). -> Development and debugging of B should only depend on the last stable build of A and should not break with simultaneous development on the library A.
  • The whole build process should be completed by executing one Bash script (once).
  • Building the project should do the following steps in order:
    1. Build module A to a jar (if unavoidable also build B).
    2. Build (or rebuild) module B using the jar generated in step 1. to an executable jar.
    3. Build module C at any time during the build process.

Is there an elegant solution using maven for doing this?

KasparJohannes
  • 520
  • 2
  • 7
  • 26
  • 1
    Check [this](https://stackoverflow.com/questions/9542974/maven-embed-dependency-artifact-code-in-jar) or [this](https://stackoverflow.com/questions/574594/how-can-i-create-an-executable-jar-with-dependencies-using-maven) with relevant comments – zolv May 21 '19 at 23:21

2 Answers2

2

Since Maven 3.5.0-beta, there is a revision field used to manage multi-module projects.

https://maven.apache.org/maven-ci-friendly.html

You basically need you parent pom.xml to look like

<project>
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>...</groupId>
    <artifactId>...</artifactId>
    <version>...</version>
  </parent>
  <groupId>...</groupId>
  <artifactId>...</artifactId>
  <version>${revision}</version>
  ...

  <properties>
    <revision>1.0.0-SNAPSHOT</revision>
  </properties>
</project> 

And then your submodule A (child) would look like

<project>
  <modelVersion>...</modelVersion>
  <parent>
    <groupId>...</groupId>
    <artifactId>...</artifactId>
    <!-- Make sure you have maven 3.6.0 at least for this to work -->
    <version>${revision}</version> 
  </parent>
  <groupId>...</groupId>
  <artifactId>...</artifactId>
  <!-- Don't put version, it's taken from the parent -->
  ...
</project>

And finally your module B looks like this

<project>
  <modelVersion>...</modelVersion>
  <parent>
    <groupId>...</groupId>
    <artifactId>...</artifactId>
    <version>${revision}</version> 
  </parent>
  <groupId>...</groupId>
  <artifactId>...</artifactId>
  ...
  <dependency>
    <groupId>...</groupId>
    <artifactId>module-A</artifactId>
    <version>${project.version}</version>
  </dependency>
  ...
</project>

Your module C will most likely look like the module A but with no dependencies

This should make your pom work locally. If you need to deploy those, you will also need to add a flatten plugin that will take your pom.xml and replace the variables revision with the actual version of your project.

 <build>
  <plugins>
    <plugin>
      <groupId>org.codehaus.mojo</groupId>
      <artifactId>flatten-maven-plugin</artifactId>
      <version>1.1.0</version>
      <configuration>
        <updatePomFile>true</updatePomFile>
        <flattenMode>resolveCiFriendliesOnly</flattenMode>
      </configuration>
      <executions>
        <execution>
          <id>flatten</id>
          <phase>process-resources</phase>
          <goals>
            <goal>flatten</goal>
          </goals>
        </execution>
        <execution>
          <id>flatten.clean</id>
          <phase>clean</phase>
          <goals>
            <goal>clean</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
  </build>

You should also be able to build your projects independently using mvn clean package -pl module-A, even though I would recommend you build A and B at the same time at least.

Sunny Pelletier
  • 329
  • 2
  • 13
  • 1
    I do not see yet how ´${revision}` helps you in managing multi-module. – J Fabian Meier May 22 '19 at 09:57
  • 1
    It ensures your dependencies will have the same version as your component. Otherwise, you will have version problems within your dependencies. This is the way maven fixed the problem. With this method, you only have to update the version at one place and it will update everywhere all by itself. – Sunny Pelletier May 22 '19 at 16:06
  • 1
    Traditionally, you just use ${project.version} for that. – J Fabian Meier May 23 '19 at 17:08
1

In Maven, you have generally two choices:

  1. Define three projects A, B and C.
  2. Define one multi-module project that contains A, B and C as modules.

In either case, you describe dependencies by using Maven dependencies in the pom.xml.

Multi-module projects are usually build in one go, so compiling all the code and using the same version number for all three modules. This would violate your idea of "building against the last stable version" because you would always depend on the newest version of A when you build.

If you define three different projects, you don't have these restrictions (and C seems to be independent anyway). Two problems remain: You need to update the version of A in the dependency - which can be done with the versions plugin. And you want to construct a "one-click build". The easiest approach would probably be a pipeline in Jenkins (or whatever your build server is), but you can also write a shell script that calls Maven thrice.

J Fabian Meier
  • 33,516
  • 10
  • 64
  • 142