In the Java module system, what is the difference between `exports` and `opens` for a package?
answer
- exports = compile + run, public only, no reflection of internals
- opens = run-time deep reflection, includes private members
- Frameworks (Jackson/Hibernate/Spring) need opens
- Both can be qualified 'to <module>'
- open module = all packages opened for reflection
basics
~10 sexports lets other modules use a package's public types at compile time and run time. opens additionally lets other modules use reflection to reach into the package, including its private members.
solid answer
~40 sBoth declarations appear in `module-info.java`. `exports a.b.c;` makes the public API of package `a.b.c` available to other modules for normal compile-time and run-time access — you can call public methods of public classes. It does NOT grant reflective access to non-public members. `opens a.b.c;` grants deep reflective access at run time: another module can use reflection (including `setAccessible(true)`) to read and invoke even private fields and methods. `opens` does not, by itself, give normal compile-time access. Frameworks like Jackson, Hibernate, or Spring need `opens` (or `open module`) to inject and read private fields. The rule of thumb: `exports` is for your public API surface; `opens` is for letting a reflection-based library look inside. You can also qualify either to specific modules: `exports a.b.c to com.example.client;`.
code
java · 11 linesmodule com.example.app {
// Public API: other modules can import and call these types normally.
exports com.example.app.api;
// Internal data objects: only Jackson may reflect into private fields.
opens com.example.app.model to com.fasterxml.jackson.databind;
// Both: usable as API AND reflectable by everyone.
exports com.example.app.dto;
opens com.example.app.dto;
}go deeper
Knows exports shares a package's public API and opens is needed for reflection-based libraries.
Explains that exports is compile+run public access while opens is run-time deep reflection including private members, and names which frameworks need opens.
Articulates the orthogonality, uses qualified exports/opens to keep holes minimal, and knows open module semantics and the InaccessibleObjectException failure mode.
Sets module-design policy: minimal qualified opens for framework integration, separating API packages from reflected model packages, and weighs strong encapsulation against framework convenience across a multi-module build.
## Background: what a module is The **Java Platform Module System (JPMS)**, introduced in Java 9, groups packages into a named unit called a **module**. A module is described by a file `module-info.java` at the root of its source, which compiles to `module-info.class`. Inside it you declare what the module needs and what it offers. A tiny example: ```java module com.example.app { requires com.example.lib; // I depend on another module exports com.example.app.api; // I let others use this package's public API opens com.example.app.model; // I let others reflect into this package } ``` ## The problem these keywords solve Before modules, every public class in any JAR on the classpath was visible to everyone, and reflection could reach *anything*. Modules introduce **strong encapsulation**: by default, packages inside a module are completely hidden from other modules. You must explicitly open holes. `exports` and `opens` are two *different kinds* of holes. ## `exports` — normal access to a public API `exports a.b.c;` says: *other modules that read mine may use the **public** types in package `a.b.c` the normal way.* "Normal way" means: - **Compile time:** their code can `import a.b.c.Foo;` and call `Foo`'s public/protected members. The compiler allows it. - **Run time:** the JVM allows the same access at execution. Crucially, `exports` only exposes what is *already* `public` (and `protected` members of public classes, to subclasses). Package-private and private members stay hidden. And `exports` gives **no** special reflective powers: you cannot use reflection to call a private method of an exported type from another module. ## `opens` — deep reflective access `opens a.b.c;` says: *at **run time**, other modules may use **reflection** to access **all** members of all types in `a.b.c`, including non-public classes and private fields/methods, including calling `setAccessible(true)`.* What `opens` does **not** do: it does not grant normal compile-time access. If a package is `opens` but not `exports`, you cannot `import` its types and call them directly in source code — you can only reach them reflectively at run time. ## Why both exist They serve two different consumers: 1. **API consumers** call your code directly. They need `exports`. 2. **Reflection-based frameworks** (JSON mappers like Jackson, ORMs like Hibernate, dependency injection like Spring, serialization, testing tools) inspect and mutate your objects' *private* internals at run time. They need `opens`. For example, Jackson sets a private field directly when deserializing JSON into your object; without `opens`, that throws `InaccessibleObjectException`. A package can be both exported and opened, just exported, just opened, or neither. ## Qualified forms Both can be restricted to named modules: ```java exports a.b.c to com.example.client; // only this module gets compile/run access opens a.b.c to com.fasterxml.jackson.databind; // only Jackson can reflect ``` Qualified exports/opens keep the hole as small as possible — good for internal-but-shared packages. ## `open module` If you write `open module com.example.app { ... }`, **every** package in the module is implicitly opened for reflection (but you still must `exports` packages for normal access). This is a blunt convenience for legacy code or heavily reflected modules. ## The mental model - `exports` = "you may *use my public API* the normal way (compile + run)." - `opens` = "you may *reflect into my internals* at run time, even private parts." They are orthogonal: one is about ordinary access to public things, the other is about reflective access to everything.
- If I only `exports` a package but a JSON library reflects into a private field of one of its types, what happens?At run time the library hits `InaccessibleObjectException` when it calls `setAccessible(true)` (or tries to access the private member), because `exports` does not grant deep reflective access. You need `opens` (ideally qualified to that library) for that package.
- What does `open module` do versus listing individual `opens`?`open module` implicitly opens every package in the module for reflection. Individual `opens` directives open only the named packages, keeping encapsulation tighter. `open module` does not replace `exports` — you still need `exports` for normal compile-time access.
exports is putting goods in a shop window others can buy through the front door. opens is giving someone a key to walk into the back room and rummage through everything, even the locked drawers.
saying these in an interview costs you the question
- Saying `exports` grants reflective access to private members — it does not.
- Saying `opens` lets you import and call the package's types in source code — it only enables run-time reflection.
- Claiming a package must be exported before it can be opened — they are independent.
- Thinking `open module` also handles normal (non-reflective) access — it does not; `exports` is still required.