Skip to Content
Course content

182: Defining Modules with module-info.java

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Wait, what actually goes inside a module-info.java file?

Think of the module-info.java file as the "manifest" or the boundary fence for your code. It's a special file that must sit at the root of your source folder. Instead of just letting every public class be visible to the entire world, you explicitly declare who you need and who can see you.

Let's say we're building a payment system. We have a module called com.payment.core. Here is what a basic definition looks like:

module com.payment.core {
    requires java.sql; // I need the SQL module to talk to the database
    exports com.payment.core.api; // Only classes in this package are visible to other modules
}

The requires keyword tells the JVM, "I can't run without this other module." The exports keyword is where the real power is; it tells the JVM, "I'm allowing other modules to use the classes in this specific package." If a package isn't exported, it's effectively private to the module, even if the classes inside it are marked public.

Why is my code not compiling even though the class is public?

This is the most common frustration when moving to the Java Module System. In the old days, if a class was public, any other class on the classpath could touch it. Not anymore. Now, you have two layers of security: the public modifier and the exports clause.

I've seen developers spend an hour debugging this. They have a class PaymentProcessor marked as public in the package com.payment.core.internal, but they forgot to export that package in module-info.java. To the outside world, that class is now invisible.

If you want another module—say, com.payment.app—to use your processor, you must explicitly export it:

module com.payment.core {
    exports com.payment.core.internal; 
}

My advice? Keep your exports list as small as possible. Only export the API packages that other people need to see. Hide your implementation details in non-exported packages.

What is the point of "requires transitive"?

Sometimes you have a dependency chain. Imagine our com.payment.core module uses a third-party logging module called com.logger.util. Now, imagine another module, com.payment.app, depends on com.payment.core. If the app needs to use those logging tools too, it would normally have to requires com.logger.util explicitly.

That gets tedious if you have a deep stack of dependencies. That's where requires transitive comes in. It's basically saying, "If you depend on me, you get this other module for free."

module com.payment.core {
    requires transitive com.logger.util;
    exports com.payment.core.api;
}

Now, when com.payment.app adds requires com.payment.core;, it automatically gains access to com.logger.util. Use this sparingly, though. If you over-use it, you end up creating a giant web of dependencies that's just as messy as the classpath we were trying to escape.




📋 Practical Task

Exercise: Implementing a Modular Currency Converter

Your task is to set up a modular project consisting of two modules: com.converter.engine and com.converter.cli.

  • Module 1 (com.converter.engine):
    • Create a package com.converter.engine.api containing a public class CurrencyService with a method convert(double amount).
    • Create a package com.converter.engine.internal containing a public class ExchangeRateProvider.
    • Create a module-info.java that exports com.converter.engine.api but does not export com.converter.engine.internal.
  • Module 2 (com.converter.cli):
    • Create a module-info.java that requires com.converter.engine.
    • Create a Main class that attempts to instantiate CurrencyService (this should work).
    • Create a line of code that attempts to instantiate ExchangeRateProvider.

Goal: Verify that the project compiles when accessing CurrencyService, but fails with a compilation error when you try to access ExchangeRateProvider, proving that your module boundaries are correctly enforced.

Rating
0 0

There are no comments for now.

to be the first to leave a comment.