20250205 ‐ Java more - cywongg/2025 GitHub Wiki
Below is a high-level explanation (in beginner-friendly terms) of why you might see the “error creating bean with name 'springSecurityFilterChain'” (or something similar) along with a “nested exception” about reflection and “cannot make java.lang.ClassLoader.defineClass accessible.” Then we’ll walk through practical steps on how to troubleshoot and fix it.
1. What Is Happening?
The Main Error
You might have seen something like:
• “Error creating bean with name 'springSecurityFilterChain' defined in class path…”
• Caused by: “Unable to make protected final java.lang.ClassLoader.defineClass … accessible … module java.base does not ‘opens java.lang’ …”
When Spring tries to create the “springSecurityFilterChain” bean (or any other bean), it often relies on various libraries behind the scenes. Some of these libraries might use reflection (think: “looking under the hood” of classes) to dynamically create proxies, manipulate classes, or do other advanced tricks.
The Nested Exception
Behind that top-level “error creating bean…” message, the underlying cause (the “nested exception”) is the reflection problem:
“Unable to make protected final java.lang.ClassLoader.defineClass … accessible…”
This specifically means that Spring (or a library it uses) is trying to call an internal Java method (like ClassLoader.defineClass
) that is blocked under the newer Java Module System (introduced in Java 9, but more strictly enforced in Java 17).
2. Why Does This Error Appear in Java 17 but Not in Java 11?
With each new Java release after Java 9, the module system enforces its rules more strictly.
• In older Java versions (especially Java 8), reflection on internal JDK classes was mostly unrestricted.
• In Java 11, it was partially enforced, but in many cases, older behavior still worked.
• In Java 17, many of these “old ways” of accessing internal classes or methods are blocked by default unless you explicitly opt in (via --add-opens
).
Hence, the code that worked in Java 11 can break when run in Java 17 because it’s making a reflective call that is no longer permitted.
3. How Is Spring Security Involved?
Spring Security relies on multiple underlying components (e.g., aspect-oriented programming frameworks or proxies) that might use reflection at runtime. The “springSecurityFilterChain” is a key bean that applies security filters across your application. If the framework tries to create or enhance classes dynamically—and if that enhancement depends on calling ClassLoader.defineClass
—it triggers the module-access error.
4. How to Troubleshoot
-
Examine the Full Stack Trace
• Look for the “caused by” lines. They usually reveal which class or library is triggering the reflection call.
• For instance, you might see references to “org.springframework.cglib.proxy” or “net.bytebuddy” or something indicating a library that manipulates bytecode. -
Check Your Dependencies
• Are you using an older version of Spring, Spring Boot, Spring Security, or libraries like CGLIB / ByteBuddy / Javassist?
• If so, upgrade to a newer version. Many recent versions of these libraries have tried to address reflection issues with the Java module system by using supported APIs where possible. -
Try Removing or Disabling Extra Libraries
• If you suspect a third-party library is hooking into Spring Security, remove it (temporarily) from your project. This can help you pinpoint which library is the culprit. -
Run with Debug Options
• One trick is to run your app with:--illegal-access=debug
(Although support for this flag has changed in later JDKs, it can sometimes still provide insight about which calls are being blocked.)
• Alternatively, turn on more detailed logging in your Spring configuration. This may provide more context on which reflection calls Spring is making.
5. How to Fix Without Using “-add-opens”
Ideally, you don’t want to rely on “-add-opens”. That’s just a workaround that re-opens Java internals to reflection. Here are some ways to fix the problem more permanently:
-
Upgrade Your Spring Dependencies
• Use the latest versions of Spring Boot, Spring Core, Spring Security, etc.
• Newer versions often provide solutions or alternative approaches that avoid unsafe reflection calls. -
Look for Library Patches
• If you’re using a library that’s known to do tricky bytecode manipulation (e.g., cglib, ByteBuddy, Javassist), check if there’s a more recent release that’s Java 17-friendly. -
Avoid Reflection on JDK Internals
• If it’s your own code, search your code for references toClassLoader.defineClass
, orsetAccessible(true)
on JDK classes fromjava.lang
orjava.base
. Replace or remove them if possible.
• If it’s a library, see if there’s a documented alternative. For example, certain dynamic-proxy solutions or official APIs might replace the need for the private call. -
Check Spring AOP / CGLIB Configuration
• Spring uses CGLIB proxies by default for class-based proxies if you enable certain features or if you have certain “proxyTargetClass=true” configurations. Sometimes switching to JDK dynamic proxies or adjusting your proxy settings can reduce the usage of advanced reflection.
• This might not always be an easy fix, but it’s worth investigating.
6. Use “-add-opens” as a Last Resort
If you can’t update or refactor right now, then adding --add-opens java.base/java.lang=ALL-UNNAMED
(in your IntelliJ run configuration or in your deployment scripts) is a quick fix to make the reflection calls work again:
--add-opens java.base/java.lang=ALL-UNNAMED
But keep in mind:
• This is more of a band-aid solution—long-term, it’s best to remove the need for opening up Java internals.
• Future Java versions may further restrict or deprecate these options, so relying on them could cause more breakage moving forward.
Summary and Next Steps
- You’re seeing “error creating bean ‘springSecurityFilterChain’” because Spring Security is trying to create a filter chain bean that depends on reflection.
- Within that process, a library calls a restricted Java method (
defineClass
) that Java 17 blocks by default. - To fix it:
- Update your Spring libraries to the latest versions.
- Check if a third-party library is doing reflection on JDK internals.
- Consider reconfiguring or removing that library.
- If you cannot fix it right away, use the
--add-opens
VM flag to allow that reflection at runtime.
Following these steps should help you pinpoint which part of your Spring Security setup (or third-party library) is causing the reflection error—and guide you toward a fix that will keep your app running smoothly on Java 17 and beyond.
Below are some additional steps you can take if you’ve already upgraded your Spring libraries but are still seeing the reflection/modular-access error:
1. Check for Other Libraries or Frameworks
Even if Spring itself is up to date, other libraries in your project might still be causing the reflection issues. For example, libraries that:
- Perform bytecode manipulation (e.g., ByteBuddy, Javassist, CGLIB).
- Use deeper reflection for injecting dependencies or performing runtime “magic” (e.g., older versions of some testing or mocking frameworks).
→ Action: Review your Maven/Gradle dependencies, and see whether there are older or transitive dependencies that might need upgrading.
2. Turn On More Detailed Logs or Debugging
• In your application, enable debug logs for class-loading and reflection. Sometimes you can do this by adding extra logging configs or running the JVM with certain flags:
- For older Java versions, “--illegal-access=debug” can show reflection warnings, but note that Java 17 has changed how this option works.
→ Action: Check your logs carefully to see if you can spot a specific library (“Caused by: some.library.ClassThatUsesReflection”) that’s triggering the reflection.
3. Check for Custom Code That Uses Reflection
• Look through your own code for:
- “setAccessible(true)” on methods or fields from JDK classes.
- Direct calls to “ClassLoader.defineClass” or “Unsafe” APIs.
• If you find them, see if there’s a more modern or supported alternative. For example, to dynamically load classes, you might rely on official Java reflection or a safer library-based approach.
4. Explore Spring Configuration and Proxies
• Spring uses proxies (either JDK proxies or CGLIB) for features like AOP and Spring Security. Sometimes certain config flags force CGLIB usage, which may do advanced reflection.
• For instance, “@EnableAspectJAutoProxy(proxyTargetClass = true)” tells Spring to use CGLIB proxies even for classes that implement interfaces.
• If you’re comfortable and it makes sense for your app, switching from CGLIB proxies to native JDK proxies could remove or reduce the reflection that triggers “defineClass”.
→ Action: Check your application’s configuration for these flags or annotations. If you’re not specifically relying on CGLIB features, you might try disabling or removing them.
5. Consider Temporarily Using “--add-opens” as a Diagnostic Step
• While not a permanent solution, adding the JVM option can confirm whether or not your problem is due to blocked reflective accesses:
--add-opens java.base/java.lang=ALL-UNNAMED
• If enabling this flag instantly “fixes” your error, then you’ve confirmed that something is indeed trying to reflect into “java.lang”.
→ Action: Use this as a stepping stone: once it’s confirmed, systematically identify which library or piece of your code is the culprit. Then remove the flag later once the root cause is fixed.
6. Seek Patches or Known Issues from the Library Authors
• If a particular library is at fault, check its GitHub repo or issue tracker. Sometimes you’ll see a description like:
“Bug: Reflection fails on Java 17. Workaround: use --add-opens
or update to version X.Y.Z.”
• If you’re already on the latest version, look for open issues where the authors might have a patch or recommended approach.
7. Summary
- Make sure all other libraries besides Spring are updated.
- Turn on more detailed logs or debug modes to see which library or class is making the restricted reflection calls.
- Inspect your own code for direct reflection on private JDK methods.
- Review Spring’s proxy configuration—see if you can switch away from advanced reflection if it’s not needed.
- Use “--add-opens” as a temporary diagnostic measure to confirm reflection issues, then remove it once you find the culprit.
Following these steps should help you pinpoint the remaining cause of the “module does not ‘open …’” error even after you’ve upgraded your Spring libraries.