
Durgesh Tiwari
Author
The Java Platform Module System (JPMS), introduced in Java 9, added strong encapsulation and improved security to Java applications. Because of this, reflective access to classes and packages became more restricted compared to traditional Java applications.
In older Java versions, reflection could access almost any class at runtime. However, in modular Java, a module must explicitly allow reflective access to its internal packages.
Reflection access in JPMS is especially important for frameworks and libraries such as:
Spring Framework
Hibernate ORM
Dependency Injection frameworks
Serialization libraries
Testing frameworks
Reflection is a Java feature that allows applications to interact with classes dynamically at runtime.
Using reflection, a program can:
Inspect classes and metadata at runtime
Access fields and methods dynamically
Create objects without direct instantiation
Invoke methods without hardcoded references

Example of Reflection
Class<?> cls = Class.forName("com.app.User");
Object obj =
cls.getDeclaredConstructor().newInstance();Here, Java dynamically loads the User class and creates its object at runtime using reflection.
Before the introduction of Java modules, reflection had very limited restrictions and could access most classes at runtime.
Because of this:
Internal classes and members could be accessed easily
Frameworks relied heavily on unrestricted reflection
Private implementation details were often exposed indirectly
Why this became a problem
Although this flexibility was useful, it also introduced several issues:
Increased security risks
Weak encapsulation of internal code
Accidental use of internal APIs that were never meant to be public
JPMS introduced strong encapsulation, which means reflective access is restricted by default unless explicitly allowed.
What Gets Restricted?
Non-exported packages remain hidden
Internal classes cannot be accessed through reflection
Private members receive stronger protection
Deep reflection access is limited in modular applications
Example
module com.app.core {
exports com.app.api;
}Here:
com.app.api is accessible to other modules
Internal packages remain hidden by default
If reflection tries to access hidden packages, Java throws access-related errors at runtime.
When reflection tries to access restricted classes or members in a modular application, Java may throw access-related exceptions.
InaccessibleObjectException
java.lang.reflect.InaccessibleObjectExceptionThis exception occurs when reflection attempts to access internal or restricted members that are not open for reflective access.
IllegalAccessException
This exception occurs when the required reflective access permissions are not granted properly.
It usually happens when:
A class or member is not accessible
The module does not allow reflective access
Access rules defined by JPMS are violated
To support reflection in a controlled way, JPMS provides the opens keyword.
The opens keyword allows a package to be accessed through reflection at runtime without fully exposing it for normal compile-time access.
This is mainly used by frameworks like Spring, Hibernate, and serialization libraries that rely on reflection.
Example
module com.app.core {
opens com.app.model;
}👉 Meaning:
Reflection frameworks can access this package
Package is not fully exported to all modules
Feature |
|
|
|---|---|---|
Purpose | Provides normal package access to other modules | Allows reflective access at runtime |
Access Time | Compile-time access | Runtime access |
Mainly Used By | Other Java modules | Reflection-based frameworks |
Visibility | Package becomes accessible for normal usage | Package is accessible only through reflection |
Encapsulation | Exposes package APIs | Keeps normal access restricted while allowing reflection |
Common Usage | Module communication | Spring, Hibernate, serialization frameworks |

JPMS also allows packages to be opened only to specific modules instead of exposing them to everyone.
Example
module com.app.core {
opens com.app.entity to spring.core;
}👉 Meaning:
Only spring.core can access the package reflectively
Other modules remain restricted

Reflection in modular Java applications comes with several runtime restrictions.
Hidden packages cannot be accessed reflectively
Private members receive stronger protection
Deep reflection requires explicit permission
Internal JDK APIs are heavily restricted
These restrictions were introduced to improve:
Security
Stability
Encapsulation
Long-term maintainability
In some situations, frameworks need access to private or internal members of a module. This is commonly referred to as breaking encapsulation.
Common Cases
Dependency Injection frameworks
ORM frameworks like Hibernate
Serialization libraries
Testing and mocking tools

Using opens: Allows reflective access to a specific package.
opens com.app.entity;Using open module: Opens all packages in the module for reflection.
open module com.app.core {
}Using JVM Flags
--add-opens👉 Commonly used during migration, testing, or compatibility handling when reflective access is required temporarily.
Reflection is a powerful feature, but excessive or uncontrolled reflective access can create security and maintenance issues in large applications.
Security Benefits of JPMS
JPMS improves application security by:
Restricting access to internal packages
Preventing accidental use of internal APIs
Protecting sensitive implementation details
Reducing unauthorized reflective access
Enforcing stronger encapsulation between modules
Allowing reflective access to too many packages can create several problems in modular applications.
Common risks
Breaks strong encapsulation
Exposes sensitive internal code
Increases potential security vulnerabilities
Makes applications harder to maintain and debug
Deep reflection refers to accessing internal members such as:
Private fields
Private methods
Internal constructors
In JPMS, deep reflection is restricted by default unless the package is explicitly opened.
Spring Framework
Hibernate ORM
Jackson
Testing and mocking frameworks

Reflection is widely used in modern Java frameworks for dynamic object handling and runtime processing.
Spring Framework → bean creation and dependency injection
Hibernate → entity mapping and proxy generation
Jackson → JSON serialization and deserialization
JUnit → automatic test discovery and execution
Java Serialization → object reconstruction at runtime
Reflection access in JPMS is an important concept in modern Java development. The Java Module System improves security and modularity by restricting uncontrolled reflective access.
Using features like:
opens
selective package access
controlled reflection permissions
developers can safely integrate modern frameworks while still maintaining strong encapsulation and secure modular architecture.