[Bug] ClassLoaderUtils.runAsClassLoader restores a stale context classloader captured at class-init time
- Dominant language
- Java
- Stars
- 4.3k
- Forks
- 1.1k
- Avg merge
- 13h 35m
- Merged PRs (30d)
- 2
Description
### Search before asking
- [X] I had searched in the [issues](https://github.com/apache/streampark/issues?q=is%3Aissue+label%3A%22bug%22) and found no similar issues referencing `ClassLoaderUtils` / `runAsClassLoader`.
### Java Version
Temurin 21.0.11 (console), built with Microsoft OpenJDK 11.0.28
### Scala Version
2.12.x
### StreamPark Version
3.0.0-SNAPSHOT (`dev` branch, commit `9ddda84c9`)
### Flink Version
1.20.4 and 2.2.1 (official binary distributions, standalone/remote cluster)
### Deploy mode
remote
### What happened
`ClassLoaderUtils.runAsClassLoader(target, supplier)` is meant to run a block under a given classloader and then put the calling thread back the way it found it. It does not: the `finally` restores `ORIGINAL_CLASS_LOADER`, a `static final` field initialised to `Thread.currentThread().getContextClassLoader()` **at class-initialisation time** — i.e. the context classloader of whichever thread first touched this class.
```java
private static final ClassLoader ORIGINAL_CLASS_LOADER = Thread.currentThread().getContextClassLoader();
public static R runAsClassLoader(ClassLoader targetClassLoader, Supplier supplier) {
try {
Thread.currentThread().setContextClassLoader(targetClassLoader);
return supplier.get();
} finally {
Thread.currentThread().setContextClassLoader(ORIGINAL_CLASS_LOADER); // <-- not the caller's
}
}
```
The method is called from shared thread-pool threads, so for any caller whose context classloader was not that same value on entry, the "restore" silently installs a *different* classloader on that thread and leaves it there. Nothing fails at the call site; the damage lands on whatever runs on that pooled thread next.
The correct behaviour is to capture the calling thread's own value on entry and restore that. `ORIGINAL_CLASS_LOADER` is still needed by `cloneClassLoader()` and stays.
This is not a regression from the recent Scala-to-Java migration — `git log -p` shows the Scala version had the same shape.
### Are you willing to submit PR?
- [X] Yes I am willing to submit a PR!
### Code of Conduct
- [X] I agree to follow this project's [Code of Conduct](https://www.apache.org/foundation/policies/conduct)
Contributor guide
No contributing guide indexed for this repository
Research direction
Search the repository for ClassLoaderUtils.runAsClassLoader and read its implementation, especially the context-classloader handling and the existing cloneClassLoader use of ORIGINAL_CLASS_LOADER. Verify the change with the relevant existing tests or add a focused test showing that a caller's context classloader is restored after the supplier runs.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 70/100