[ISSUE #10612] Allow controller startup on JDK 17 via --add-opens#10638
[ISSUE #10612] Allow controller startup on JDK 17 via --add-opens#10638123123213weqw wants to merge 1 commit into
Conversation
On JDK 9+ the controller path (both controller-in-namesrv and the standalone mqcontroller) fails at startup with InaccessibleObjectException, because the Hessian SerializerFactory (pulled in transitively via DLedger, used by ReplicasInfoManager) reflectively accesses java.lang.StackTraceElement.classLoaderName during its <clinit>, which JDK 9+ strong encapsulation denies. Add `--add-opens java.base/java.lang=ALL-UNNAMED` to the JDK 9+ branch of runserver.sh (the same script both startup paths go through). The JDK < 9 branch is untouched, since `--add-opens` is an unrecognized option on Java 8. Verified the fix end-to-end with a minimal reproducer that performs the same reflective access: - JDK 17 without --add-opens: InaccessibleObjectException (matches the stack trace in apache#10612 / apache#10170) - JDK 17 with --add-opens: reflective access succeeds - JDK 8 with --add-opens: "Unrecognized option" (confirms the JDK 9+ branch guard is required) Also fixes apache#10170 (duplicate of the same root cause).
|
Nice minimal fix. One question for scope confirmation: does the same |
|
@itxaiohanglover good question — I should have called this out in the body. The reflective access is specific to the controller path:
So the scope of this PR is "fix controller startup on JDK 17 via the shared I'll add a one-line scope note to the PR body to make that explicit for future readers. |
RockteMQ-AI
left a comment
There was a problem hiding this comment.
Review by github-manager-bot
Summary
Adds --add-opens java.base/java.lang=ALL-UNNAMED to the JDK 9+ branch of runserver.sh, fixing InaccessibleObjectException during controller startup on JDK 17. Closes #10612 and #10170.
Findings
- [Info]
distribution/bin/runserver.sh:96-102— The 7-line comment is thorough and well-justified. It clearly traces the root cause: HessianSerializerFactory→ DLedger →ReplicasInfoManager→ reflective access toStackTraceElement.classLoaderName. This makes future maintainers' lives much easier. - [Info]
distribution/bin/runserver.sh:103— The scope is deliberately narrow (java.base/java.langonly), which is the right call. If other JDK packages need opening later, it's a one-line addition. - [Info]
distribution/bin/runserver.sh:93— Correctly placed inside theelse(JDK 9+) branch, so JDK 8 users are completely unaffected. Good defensive placement.
Suggestions
- Consider adding the equivalent
--add-openstorunserver.cmd(Windows) as a follow-up. The PR body already acknowledges this gap, so a tracking issue or follow-up PR would close the loop for Windows users.
Verdict
Clean, minimal, well-documented fix. The PR body is excellent — clear problem statement, root cause chain, and verification table. LGTM.
Automated review by github-manager-bot
|
@itxaiohanglover addressed — added a "Scope" section to the PR body with a table covering broker/proxy/controller/startup-script, plus the grep result showing Hessian is only used in |
RockteMQ-AI
left a comment
There was a problem hiding this comment.
LGTM. Targeted fix for the controller startup failure on JDK 17.
The --add-opens java.base/java.lang=ALL-UNNAMED is correctly placed in the JDK 9+ branch of choose_gc_options(), and the comment clearly explains the root cause (Hessian SerializerFactory reflective access to StackTraceElement.classLoaderName via DLedger) and references both #10612 and #10170.
While --add-opens is a workaround rather than a proper fix, it is the pragmatic solution here since the problematic reflective access is in a transitive dependency (DLedger → Hessian). A proper upstream fix would require changes in those libraries.
Automated review by github-manager-bot
|
Thanks for the thorough scope confirmation and the table in the PR body — controller-only makes sense given the grep result showing Hessian is used solely in |
|
@fuyou001 thanks for the APPROVED! The PR is Happy to make any other changes if needed. |
What
Allows the controller path (both controller-in-namesrv and the standalone
mqcontroller) to start on JDK 17 by adding--add-opens java.base/java.lang=ALL-UNNAMEDto the JDK 9+ branch ofrunserver.sh.Why
Closes #10612. Also closes #10170 (duplicate, same root cause).
On JDK 9+, the controller fails at startup with
InaccessibleObjectException:The Hessian
SerializerFactory(pulled in transitively via DLedger, used byReplicasInfoManagerforbrokerReplicaInfoserialization) reflectively accessesjava.lang.StackTraceElement.classLoaderNameduring its static initializer. JDK 9+ strong encapsulation denies that access by default.The user-confirmed workaround in #10170 is precisely this JVM flag; this PR puts it in the right branch of the shipped script so users don't have to roll their own.
How
runserver.shalready detectsJAVA_MAJOR_VERSIONand branches at line 87. This PR adds the--add-opensto theelse(JDK 9+) branch only, so JDK 8 — which doesn't recognize the option — is untouched.Scope is deliberately narrow: only
java.base/java.lang, because that's the only package hessian'sStackTraceElementDeserializerreaches into. If hessian (or anything else) later trips on a different JDK core package, it's a one-line addition here.Verification
Couldn't run the full controller on the test box (no maven), so I verified the mechanism directly with a minimal reproducer that performs the same reflective access:
Results on the test box (Ubuntu 22.04, OpenJDK 17.0.19 + OpenJDK 1.8.0_492):
java TestAddOpensInaccessibleObjectException(matches the issue's stack trace)java --add-opens java.base/java.lang=ALL-UNNAMED TestAddOpensOK: nulljava --add-opens java.base/java.lang=ALL-UNNAMED TestAddOpensUnrecognized option: --add-opens(confirms the JDK 9+ branch guard is required)bash -n runserver.shclean.Notes for reviewers
Scope: which startup paths does this affect?
The reflective Hessian access (
com.caucho.hessian.io.SerializerFactory.<clinit>) is specific to the controller path.grep -rln com.caucho --include='*.java'returns exactly one file in the whole tree:controller/src/main/java/org/apache/rocketmq/controller/impl/manager/ReplicasInfoManager.java.runserver.shmqnamesrv(incl. controller-in-namesrv),mqcontroller,mqproxyrunbroker.shmqbroker,mqbrokercontainerSo this PR fully closes #10612 and the duplicate #10170. It is not claiming to fix a Hessian issue on broker/proxy, because there isn't one.
SerializerFactoryand overridinggetClassDeserializer) because:runserver.shis used by both startup paths, so a single change covers both.SerializerFactorycould be wrapped to skip theStackTraceElementDeserializerregistration, which would also let us drop the JVM flag eventually..cmd(runserver.cmd) doesn't have the equivalent fix — let me know if you want it patched in this PR or separately; I held off because I can't verify the Windows behavior here.How to test
InaccessibleObjectExceptionfromSerializerFactory.<clinit>.