123123213weqw opened a new pull request, #10638:
URL: https://github.com/apache/rocketmq/pull/10638
## 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-UNNAMED` to the JDK 9+ branch of `runserver.sh`.
## Why
Closes #10612. Also closes #10170 (duplicate, same root cause).
On JDK 9+, the controller fails at startup with
`InaccessibleObjectException`:
```
java.lang.reflect.InaccessibleObjectException: Unable to make field private
java.lang.String java.lang.StackTraceElement.classLoaderName accessible:
module java.base does not "opens java.lang" to unnamed module @...
at
java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354)
...
at
com.caucho.hessian.io.JavaDeserializer.getFieldMap(JavaDeserializer.java:329)
at
com.caucho.hessian.io.JavaDeserializer.<init>(JavaDeserializer.java:97)
at
com.caucho.hessian.io.StackTraceElementDeserializer.<init>(StackTraceElementDeserializer.java:57)
at
com.caucho.hessian.io.SerializerFactory.<clinit>(SerializerFactory.java:589)
at
org.apache.rocketmq.controller.impl.manager.ReplicasInfoManager.<clinit>(ReplicasInfoManager.java:79)
at
org.apache.rocketmq.controller.impl.DLedgerController.<init>(DLedgerController.java:132)
at
org.apache.rocketmq.controller.ControllerManager.initialize(ControllerManager.java:122)
```
The Hessian `SerializerFactory` (pulled in transitively via DLedger, used by
`ReplicasInfoManager` for `brokerReplicaInfo` serialization) reflectively
accesses `java.lang.StackTraceElement.classLoaderName` during 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.sh` already detects `JAVA_MAJOR_VERSION` and branches at line 87.
This PR adds the `--add-opens` to the `else` (JDK 9+) branch only, so JDK 8 —
which doesn't recognize the option — is untouched.
```sh
else
# ... existing G1GC + Xlog options ...
# JDK 9+ strong encapsulation blocks the reflective access that the
# Hessian SerializerFactory (pulled in transitively via DLedger, used
on
# the controller path) performs against JDK core types ...
JAVA_OPT="${JAVA_OPT} --add-opens java.base/java.lang=ALL-UNNAMED"
fi
```
Scope is deliberately narrow: only `java.base/java.lang`, because that's the
only package hessian's `StackTraceElementDeserializer` reaches 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:
```java
import java.lang.reflect.Field;
public class TestAddOpens {
public static void main(String[] args) throws Exception {
Field f =
StackTraceElement.class.getDeclaredField("classLoaderName");
f.setAccessible(true);
System.out.println("OK: " + f.get(new
StackTraceElement("a","b","c",1)));
}
}
```
Results on the test box (Ubuntu 22.04, OpenJDK 17.0.19 + OpenJDK 1.8.0_492):
| JDK | Command | Result |
|-----|---------|--------|
| 17 | `java TestAddOpens` | ❌ `InaccessibleObjectException` (matches the
issue's stack trace) |
| 17 | `java --add-opens java.base/java.lang=ALL-UNNAMED TestAddOpens` | ✅
`OK: null` |
| 8 | `java --add-opens java.base/java.lang=ALL-UNNAMED TestAddOpens` | ❌
`Unrecognized option: --add-opens` (confirms the JDK 9+ branch guard is
required) |
`bash -n runserver.sh` clean.
## Notes for reviewers
- I went with the script-level fix instead of a code-level fix (subclassing
`SerializerFactory` and overriding `getClassDeserializer`) because:
1. It matches the workaround the project already endorses (#10170 comment
from @Kris20030907).
2. It's a one-line, zero-risk change.
3. The same `runserver.sh` is used by both startup paths, so a single
change covers both.
- If you'd prefer a code-level fix instead (or in addition), I'm happy to do
that — the `SerializerFactory` could be wrapped to skip the
`StackTraceElementDeserializer` registration, 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
1. Build as usual, then on a JDK 17 box:
```
sh bin/mqcontroller -c ... # or bin/mqnamesrv with
enableControllerInNamesrv=true
```
2. Before this PR: `InaccessibleObjectException` from
`SerializerFactory.<clinit>`.
3. After this PR: starts normally.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]