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.
GO TO FULL VERSION