CodeGym /Courses /JAVA 25 SELF /module-info.java: syntax, creating modules

module-info.java: syntax, creating modules

JAVA 25 SELF
Level 60, Lesson 1
Available

1. What is module-info.java and where is it located?

A module in Java always starts with the module-info.java file. It’s a kind of “passport” for the module, where you declare its name, exported packages, and dependencies on other modules.

Where to look?
The module-info.java file must be located at the root of your module’s source folder. For example, if your project structure is like this:

project-root/
└── src/
    └── my.module.name/
        ├── module-info.java
        └── com/
            └── example/
                └── api/
                    └── MyClass.java

Here, my.module.name is the module name (we’ll cover the naming rules shortly).

Without this file, a module simply isn’t considered a module!
If it’s missing, it’s a regular “old” Java project, even if it has lots of folders and classes.

2. Syntax of module-info.java: core elements

Let’s immediately look at an example of the simplest file—it’s not scary, honestly!

module my.module.name {
    exports com.example.api;
    requires java.sql;
}

Let’s break it down piece by piece:

module my.module.name { ... }
This is a module declaration with the name my.module.name. A module name is a unique identifier that usually matches the root package (for example, com.example.app).
Fun fact: if you name your module java.base, the compiler won’t be thrilled. Don’t try to masquerade as standard modules.

exports com.example.api;
This line says: “I, the module, am ready to share everything that’s in the com.example.api package.” Everything in that package marked as public will be visible to other modules. Everything else is strictly for internal use.

requires java.sql;
Here we openly admit to the compiler: “I need the standard module java.sql to work.” Without this, the compiler won’t let us use classes from that module.

Additional keywords (for general knowledge)

  • opens <package>; — opens a package for reflection (for example, for serialization libraries like Jackson).
  • uses <service-interface>; — declares that the module uses a service (interface).
  • provides <service-interface> with <implementation-class>; — declares that the module provides a service implementation.

In this lecture we’ll focus on exports and requires—they’re needed in the overwhelming majority of educational and production projects.

3. Examples of module-info.java

Example 1. Minimal module

module com.example.hello {
    exports com.example.hello.api;
}
  • This module exports only the com.example.hello.api package.
  • Anything under, for example, com.example.hello.internal will be hidden from other modules, even if there are public classes in there.

Example 2. Module with a dependency

module com.example.dbclient {
    exports com.example.db.api;
    requires java.sql;
}

We can use JDBC, but only because we explicitly declared a dependency on java.sql.

Example 3. Multiple exported packages

module com.example.library {
    exports com.example.library.api;
    exports com.example.library.utils;
}

You can export as many packages as you want (but don’t export everything indiscriminately—that defeats the purpose of modules!).

4. Constraints and rules

Module name

  • Usually matches the root package (for example, com.example.app).
  • Must not coincide with names of standard modules (java.base, java.sql, etc.).
  • Must not contain spaces or special characters, start with a digit, etc.
  • Recommendation: use your organization’s or project’s reverse domain name to avoid conflicts.

One module — one module-info.java
A module may contain only one such file. If there are two, the compiler will throw you a “modular tantrum.”

A package can be exported only from a single module
The same package cannot be exported from two different modules. It’s like having two passports under the same name—the authorities won’t approve.

Packages inside a module
You can export only those packages that actually exist in this module’s source structure. Exporting a non-existent package will result in a compilation error.

5. Practice: creating module-info.java in a project

Suppose we have a simple project with the following contents:

project-root/
└── src/
    └── com.example.greetings/
        ├── module-info.java
        └── com/
            └── example/
                └── greetings/
                    ├── api/
                    │   └── Greeter.java
                    └── internal/
                        └── SecretSauce.java

Step 1. Create module-info.java

module com.example.greetings {
    exports com.example.greetings.api;
}

Step 2. Try to use a class from the internal package in another module

Assume we have a second module com.example.app that wants to access SecretSauce:

module com.example.app {
    requires com.example.greetings;
}

import com.example.greetings.internal.SecretSauce; // ERROR!

Result:
The compiler will say: “The package com.example.greetings.internal is not exported by module com.example.greetings.” Even if the class SecretSauce is public, it is not available to other modules.
This is real encapsulation at the module level!

Step 3. Try not declaring requires

If in com.example.app we don’t write requires com.example.greetings; and try to use a class from com.example.greetings.api, the compiler will produce an error:

package com.example.greetings.api is not visible

6. Common mistakes when working with module-info.java

Error #1: Module name and project structure mismatch.
If you name the module com.example.app but the folder structure is src/main/java/app, the compiler won’t understand what you want from it. The module name usually matches the root package, and the folders should reflect that.

Error #2: Exporting everything.
Only export what truly needs to be visible to other modules. Don’t do exports com.example; just because “it’s easier.” That breaks encapsulation.

Error #3: Forgot to add requires.
If you use classes from another module or the standard library (for example, java.sql), but forget to declare the dependency, you’ll get a compilation error.

Error #4: Non-existent package in exports.
If you wrote exports com.example.foo; but such a package doesn’t exist, the compiler will say that you’re “exporting thin air.”

Error #5: Public classes in a non-exported package.
If a class is declared public but resides in a package that is not exported, that class will be visible only within the module. This isn’t an error, but it often surprises newcomers.

Error #6: Multiple module-info.java files in a single module.
There must be only one module-info.java file in a module. If there are two, the compiler won’t be able to build the project.

1
Task
JAVA 25 SELF, level 60, lesson 1
Locked
Connecting to the digital ocean of data 🌐
Connecting to the digital ocean of data 🌐
1
Task
JAVA 25 SELF, level 60, lesson 1
Locked
Unlocking the Multifaceted Library 💎
Unlocking the Multifaceted Library 💎
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION