skip to content

A framework throws `InaccessibleObjectException` (or 'Unable to make field accessible') when reflecting into your module. What is the root cause and how do you fix it correctly?

level: seniorimportance: should knowfreq 58%

answer

  1. Exception = reflection blocked because package not opened
  2. exports ≠ opens: exports won't fix reflection on private members
  3. Preferred fix: qualified `opens P to framework;`
  4. Can't edit module-info? use `--add-opens M/P=target` (ALL-UNNAMED for classpath)
  5. Error message literally names the missing opens directive

basics

~20 s

The framework is using reflection to reach into your code's private members, but your package is not opened. Modules block reflective access by default. Fix it by adding opens yourpackage; (or opens yourpackage to the.framework;) in module-info.java.

solid answer

~40 s

`InaccessibleObjectException` means reflection tried to call `setAccessible(true)` on a member of a module-encapsulated package that was not opened. By default, JPMS blocks deep reflective access even into *exported* packages — exports grants normal access to public members, not reflection into private ones. The proper fix is a directive in your `module-info.java`: `opens com.example.model to com.fasterxml.jackson.databind;` (qualified to just the framework, keeping encapsulation tight), or `opens com.example.model;` to open it to all. If you can't edit module-info — e.g. a third-party module — you use the launcher flag `--add-opens com.example.app/com.example.model=com.framework` (or `ALL-UNNAMED` for the classpath). For a legacy module that is heavily reflected over, `open module com.example.app { ... }` opens every package. Prefer qualified `opens` over blanket flags so you don't silently undo strong encapsulation.

code

java · 10 lines
java
// Fix in your own module:
module com.example.app {
    requires com.fasterxml.jackson.databind;
    opens com.example.app.model to com.fasterxml.jackson.databind; // tight, correct
}

// Can't edit module-info (3rd-party module)? launcher flag instead:
//   java --add-opens com.example.app/com.example.app.model=com.fasterxml.jackson.databind ...
// Reflecting into JDK internals from the classpath:
//   java --add-opens java.base/java.lang=ALL-UNNAMED ...

go deeper

for a junior

Knows the error means reflection is blocked and that opens is the fix.

for a middle

Distinguishes exports from opens and adds a (qualified) opens directive correctly.

for a senior

Reads the exception message to derive the exact directive, prefers qualified opens, and knows --add-opens/ALL-UNNAMED/MANIFEST escape hatches and why exports/public are wrong fixes.

for a principal

Sets policy on opens scope across many modules and frameworks, controls --add-opens proliferation in build/runtime config, and weighs reflective-framework needs against strong encapsulation and JDK-internals restrictions.

## The error `java.lang.reflect.InaccessibleObjectException` (message often: *Unable to make field private ... accessible: module X does not "opens P" to module Y*) is thrown when reflective code calls `field.setAccessible(true)` (or `method`/`constructor` `setAccessible`) on a member that the **Java Platform Module System (JPMS)** has encapsulated. ## Why it happens — the default is closed A **module** strongly encapsulates its packages. JPMS distinguishes two kinds of access: - **Normal access** to *public* members of *exported* packages — controlled by `exports`. - **Deep reflective access** to *any* member (including `private`) at run time — controlled by `opens`. Key trap: even if a package is **exported**, that does NOT grant deep reflective access. Reflection that flips `setAccessible(true)` on a non-public member needs the package to be **opened**. By default packages are not opened, so frameworks that mutate private fields fail. Why do frameworks do this? JSON mappers (Jackson), ORMs (Hibernate/JPA), DI containers (Spring), and serializers routinely read and write **private** fields of your objects via reflection. Without `opens`, the JVM refuses, and you get `InaccessibleObjectException`. ## The correct fixes (in order of preference) ### 1. Qualified `opens` in your module-info If you own the module, open exactly the package to exactly the framework: ```java module com.example.app { requires com.fasterxml.jackson.databind; exports com.example.app.api; opens com.example.app.model to com.fasterxml.jackson.databind; } ``` This is the tightest, safest fix: only Jackson can reflect into `com.example.app.model`, and only that package is exposed. ### 2. Unqualified `opens` ```java opens com.example.app.model; ``` Opens the package to *all* modules for reflection. Use when you can't name the consumer (e.g., several frameworks) but still want package-level scope. ### 3. `open module` ```java open module com.example.app { ... } ``` Every package is opened for reflection. Convenient for legacy/heavily-reflected modules, but it discards package-level encapsulation, so use sparingly. ### 4. `--add-opens` launcher/compiler flag When you **cannot** edit the offending module's `module-info` (third-party code, or a quick migration): ``` --add-opens com.example.app/com.example.model=com.framework ``` For classpath (non-modular) code use `ALL-UNNAMED` as the target: ``` --add-opens java.base/java.lang=ALL-UNNAMED ``` Flags can also go in a JAR's `MANIFEST.MF` (`Add-Opens:`) or the `JDK_JAVA_OPTIONS` env var. Treat flags as an escape hatch, not a design choice — they undo encapsulation invisibly and must be repeated everywhere the app runs. ## What does NOT fix it - Adding `exports` — that grants normal access to public members, not reflection into private ones. - Making the field `public` — reflection on a public field of an *exported* package can work, but you usually don't want to break your data model's encapsulation just to satisfy a framework; `opens` is the intended tool. - Adding `requires` — readability doesn't grant reflective access. ## How to diagnose quickly The exception message names both modules and the missing directive: *module X does not "opens P" to module Y*. Read it literally: X needs `opens P to Y;` (or you supply `--add-opens X/P=Y`). ## Note on JDK internals Reflecting into JDK internal packages (e.g., `java.base/java.lang`) is increasingly restricted; since JDK 16 illegal reflective access is denied by default, and JDK 17+ has no relaxation flag for *its own* internals beyond explicit `--add-opens`. For your own modules, just use `opens`. ## One-line takeaway `InaccessibleObjectException` = reflection without `opens`. Fix by `opens <package> to <framework>;` in module-info (preferred), or `--add-opens` when you can't edit it — never by confusing it with `exports`.

  • Why doesn't adding `exports` fix InaccessibleObjectException?
    Because `exports` only grants normal access to *public* members of a package. The framework is using reflection to touch *private* members (or to call `setAccessible(true)`), which is a separate capability controlled by `opens`. Reflection into encapsulated members needs the package opened, regardless of whether it is exported.
  • When would you use `--add-opens` instead of editing module-info.java?
    When you can't change the module descriptor — typically a third-party/library module you don't own, or during a migration before you've added proper directives. For classpath (non-modular) code, target `ALL-UNNAMED`. It's an escape hatch: it must be applied at every launch and silently weakens encapsulation, so a qualified `opens` is preferred when you control the module.

Exporting a package is like unlocking the front door for guests. The framework needs to open the safe in the bedroom — that's opens. Unlocking the front door (exports) doesn't help; you must specifically open the safe.

saying these in an interview costs you the question

  • Trying to fix it by adding `exports` instead of `opens`.
  • Making fields public to satisfy a framework rather than using `opens`.
  • Reaching for `open module` or broad `--add-opens java.base/...=ALL-UNNAMED` as a first resort instead of a qualified opens.
  • Believing `requires` or readability grants reflective access.

context