CodeGym /Courses /JAVA 25 SELF /Building multi-module projects: Maven, Gradle, IDEA

Building multi-module projects: Maven, Gradle, IDEA

JAVA 25 SELF
Level 60, Lesson 4
Available

1. Building modular projects: basic principles

Compiler and the module path (module-path)

Before modules existed, an application was compiled and run using the so‑called classpath — just a list of directories and JAR files where Java looked for classes. With the module system a new player appeared — module-path. Now the compiler and the JVM must know not only where classes are located, but also which modules they belong to, what dependencies they have, and which packages are exported.

Key point:

  • For modular projects, use --module-path instead of -classpath.
  • The compiler and the JVM must see all the modules your application needs (and their dependencies).

Example: manual compilation of modules

Suppose you have two modules: core and app, where app depends on core.

Directory layout:

project-root/
  core/
    src/
      main/
        java/
          module-info.java
          com/example/core/...
  app/
    src/
      main/
        java/
          module-info.java
          com/example/app/...

Manual compilation (demonstration):

# First compile core
javac -d out/core core/src/main/java/module-info.java core/src/main/java/com/example/core/*.java

# Then app, specifying module-path to core
javac --module-path out/core -d out/app app/src/main/java/module-info.java app/src/main/java/com/example/app/*.java

Run:

java --module-path out/core:out/app -m app/com.example.app.Main

In real projects you do not need to do this by hand — use Maven/Gradle or the IDE.

2. Maven: building multi-module projects

Multi-module project structure in Maven

Maven has long supported a structure with multiple modules (submodules). With the Java module system, these Maven “modules” often coincide with Java modules, but not always: a Maven module is just a subproject, while a Java module is what is described in module-info.java. Typically, one Maven module = one Java module.

Typical structure:

myproject/
  pom.xml                # Parent POM
  core/
    pom.xml              # Module core
    src/main/java/
      module-info.java
      com/example/core/...
  app/
    pom.xml              # Module app
    src/main/java/
      module-info.java
      com/example/app/...

Example parent POM (myproject/pom.xml):

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.example</groupId>
  <artifactId>myproject</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>pom</packaging>
  <modules>
    <module>core</module>
    <module>app</module>
  </modules>
</project>

Example POM for module core (core/pom.xml):

<project>
  <parent>
    <groupId>com.example</groupId>
    <artifactId>myproject</artifactId>
    <version>1.0-SNAPSHOT</version>
  </parent>
  <artifactId>core</artifactId>
  <dependencies>
    <!-- There can be dependencies here, for example on other modules or third-party libraries -->
  </dependencies>
</project>

Example POM for module app (app/pom.xml):

<project>
  <parent>
    <groupId>com.example</groupId>
    <artifactId>myproject</artifactId>
    <version>1.0-SNAPSHOT</version>
  </parent>
  <artifactId>app</artifactId>
  <dependencies>
    <dependency>
      <groupId>com.example</groupId>
      <artifactId>core</artifactId>
      <version>1.0-SNAPSHOT</version>
    </dependency>
  </dependencies>
</project>

Important:

  • If app requires core, the module-info.java of module app must contain requires core;
  • Maven will assemble dependencies automatically if <dependency> and <module> are configured correctly.

How Maven handles module-info.java

  • Maven automatically compiles module-info.java along with the other classes.
  • If you have modular dependencies, Maven will add them to the module-path at compile and run time.
  • If you use old plugins or Java below 9, the module system will not work.

Running a modular application via Maven

<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-compiler-plugin</artifactId>
      <version>3.10.1</version>
      <configuration>
        <release>21</release> <!-- or your Java version -->
      </configuration>
    </plugin>
    <plugin>
      <groupId>org.codehaus.mojo</groupId>
      <artifactId>exec-maven-plugin</artifactId>
      <version>3.1.0</version>
      <configuration>
        <mainClass>com.example.app.Main</mainClass>
        <commandlineArgs></commandlineArgs>
      </configuration>
    </plugin>
  </plugins>
</build>
mvn clean install
mvn -pl app exec:java

Common mistakes when working with Maven and modules

Error: “module not found”. You did not specify the correct module-path or the dependent artifact is missing a <dependency>.

Duplicate module names. The project must not contain two modules with the same name (for example, two module core).

Missing export/requires. If you forget to export a package (exports) or declare a dependency (requires), you will get a compilation error.

Mixing classpath and module-path. Do not use outdated plugins/settings that do not support modules — this leads to unpredictable errors.

3. Gradle: building multi-module projects

Project structure in Gradle

myproject/
  settings.gradle
  build.gradle
  core/
    build.gradle
    src/main/java/module-info.java
    src/main/java/com/example/core/...
  app/
    build.gradle
    src/main/java/module-info.java
    src/main/java/com/example/app/...

settings.gradle

rootProject.name = 'myproject'
include 'core', 'app'

build.gradle (root)

subprojects {
    apply plugin: 'java'

    java {
        toolchain {
            languageVersion = JavaLanguageVersion.of(21) // or your Java version
        }
    }

    repositories {
        mavenCentral()
    }
}

build.gradle for core

plugins {
    id 'java'
}

group = 'com.example'
version = '1.0-SNAPSHOT'

build.gradle for app

plugins {
    id 'java'
    id 'application'
}

group = 'com.example'
version = '1.0-SNAPSHOT'

dependencies {
    implementation project(':core')
}

application {
    mainModule = 'app' // Your Java module name
    mainClass = 'com.example.app.Main'
}

Build and run

./gradlew build
./gradlew :app:run

Gradle determines the module-path automatically if it finds module-info.java. If something does not work, check that you are using a recent version of Gradle and its plugins.

4. IntelliJ IDEA: creating and configuring a modular project

Creating a modular project

  • File → New → Project → Java → enable “Create module-info.java”.
  • For a multi-module project: File → New → Module — add new modules to the project.
  • If you use Maven/Gradle, just import the project by pom.xml or build.gradle.

Structure in IDEA

  • In Project View, each module is shown as a separate branch.
  • Each module has its own module-info.java and its own sources.
  • IDEA suggests which modules export/require which packages (exports/requires).
  • If you forget to export a package or declare a dependency, IDEA will highlight an error.

Checking module-path, running the main class

  • In Run/Debug Configurations specify:
    • Main class (for example, com.example.app.Main)
    • Module (for example, app)
  • IDEA will take care of the module-path.
  • If you run via Maven/Gradle — use the corresponding configurations (for example, app [run]).

Importing third-party modules and libraries

  • To work with external libraries (for example, requires java.sql; or third-party JARs) — add a dependency via Maven/Gradle.
  • If a library is not modular (no module-info.java), it will be automatically added to the “unnamed module” (this is fine for most libraries).

5. Practice: creating a simple multi-module project

Step 1. Create the project structure

myproject/
  core/
    src/main/java/module-info.java
    src/main/java/com/example/core/HelloService.java
  app/
    src/main/java/module-info.java
    src/main/java/com/example/app/Main.java

HelloService.java (core):

package com.example.core;

public class HelloService {
    public String getHello() {
        return "Hello from the core module!";
    }
}

module-info.java (core):

module core {
    exports com.example.core;
}

Main.java (app):

package com.example.app;

import com.example.core.HelloService;

public class Main {
    public static void main(String[] args) {
        HelloService service = new HelloService();
        System.out.println(service.getHello());
    }
}

module-info.java (app):

module app {
    requires core;
}

Step 2. Build and run with Maven

In the project root, create the parent pom.xml and two subprojects (core/pom.xml, app/pom.xml) as above. In app/pom.xml add a dependency on core.

mvn clean install
mvn -pl app exec:java

Step 3. Build and run with Gradle

Create settings.gradle, the root build.gradle, and one per module. In app/build.gradle declare the dependency on core and set mainClass.

./gradlew build
./gradlew :app:run

Step 4. Import and run in IntelliJ IDEA

  • Open the project root via File → Open.
  • IDEA recognizes the Maven/Gradle structure and creates modules.
  • In each module you can open module-info.java; IDEA will show relationships between modules.
  • Run Main.java via the context menu (“Run Main.main()”) — IDEA will set the module-path automatically.

6. Common errors when building modular projects

Error #1: Incorrect module-path. If at run time or compile time you see a message like “module not found” or “package is not visible”, you most likely did not specify the correct module-path or forgot to add a dependency in pom.xml/build.gradle.

Error #2: Duplicate module names. The project must not contain two modules with the same name (for example, two module core). This leads to a compilation error.

Error #3: Non-exported package. If a class is in a package that is not exported via exports in module-info.java, it will be inaccessible to other modules even if it is public. A compilation error will occur when attempting to use such a class.

Error #4: Missing requires. If a module uses classes from another module but does not specify requires in module-info.java, the compiler will report an error.

Error #5: Incompatibility with external libraries. Mismatching modules and libraries without module-info.java (they end up in the “unnamed module”) usually does not get in the way, but in some configurations additional setup may be required.

Error #6: Launching from the wrong module. In the run configuration of IDEA or Maven/Gradle, an incorrect main class or module is specified — the application does not start. Check Main, mainModule/module, and the profile used.

1
Task
JAVA 25 SELF, level 60, lesson 4
Locked
Building a Multimodule Project Fortress 🏰
Building a Multimodule Project Fortress 🏰
1
Task
JAVA 25 SELF, level 60, lesson 4
Locked
Starting the application's heart with Maven ✨
Starting the application's heart with Maven ✨
1
Survey/quiz
Modules and project structure, level 60, lesson 4
Unavailable
Modules and project structure
Modules and project structure
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION