refactor: replace sun.reflect.Reflection with StackWalker in Reflect#3151
Merged
Conversation
pjfanning
reviewed
Jun 23, 2026
| val m = c.getMethod("getCallerClass", Array(classOf[Int]): _*) | ||
| Some((i: Int) => m.invoke(null, Array[AnyRef](i.asInstanceOf[java.lang.Integer]): _*).asInstanceOf[Class[?]]) | ||
| val walker = java.lang.StackWalker.getInstance( | ||
| java.util.Set.of(java.lang.StackWalker.Option.RETAIN_CLASS_REFERENCE)) |
Member
There was a problem hiding this comment.
why do we need java.lang.StackWalker instead of using StackWalker?
He-Pin
added a commit
that referenced
this pull request
Jun 23, 2026
…oader
Motivation:
The main PR replaced `sun.reflect.Reflection.getCallerClass` (a JDK 8
internal API that returns `None` on JDK 17 because
`Class.forName("sun.reflect.Reflection")` no longer resolves) with the
official `java.lang.StackWalker` API. The previous spec had no
coverage of `getCallerClass` itself, so a silent regression — for
example reverting the implementation back to the `sun.reflect` path —
would not be caught.
Modification:
Add four tests to `ReflectSpec`:
- `Reflect.getCallerClass` is defined on JDK 17+ (the old
implementation always returned `None`; this is the directional test
that fails on the pre-PR code).
- `getCaller(0)` returns a non-null `Class` whose name starts with
`org.apache.pekko.util.Reflect`, validating the frame-skip
semantics.
- `getCaller(Int.MaxValue)` returns `null` for a depth beyond the
stack, matching the `findCaller` contract that filters `ne null`.
- `Reflect.findClassLoader()` returns a non-null `ClassLoader` for
the end-to-end path.
Result:
StackWalker migration is now protected by a directional test that
would fail on the pre-PR implementation.
Tests:
sbt "actor-tests/Test/testOnly org.apache.pekko.util.ReflectSpec" --
10/10 passed (4 new + 6 pre-existing findConstructor tests).
References:
Discovered during internal review of PR #3151.
Motivation: Reflect.getCallerClass uses sun.reflect.Reflection.getCallerClass via reflection, a JDK 8 internal API that was moved to jdk.internal.reflect.Reflection in JDK 9+. On JDK 17+ without --add-opens for jdk.internal.reflect, this always falls back to None. Modification: Replace with java.lang.StackWalker (JDK 9) with RETAIN_CLASS_REFERENCE option, which is the official supported API for accessing caller class information. The API contract is preserved: given a frame depth index, returns the Class at that depth (or null if beyond stack). Result: Official JDK API instead of internal reflection hack. StackWalker was already established in the codebase (LoggerClass.scala, TestKitUtils.scala). The findClassLoader fallback now works reliably on JDK 17+. Tests: sbt "actor/compile" — passed References: Refs #3136
…oader
Motivation:
The main PR replaced `sun.reflect.Reflection.getCallerClass` (a JDK 8
internal API that returns `None` on JDK 17 because
`Class.forName("sun.reflect.Reflection")` no longer resolves) with the
official `java.lang.StackWalker` API. The previous spec had no
coverage of `getCallerClass` itself, so a silent regression — for
example reverting the implementation back to the `sun.reflect` path —
would not be caught.
Modification:
Add four tests to `ReflectSpec`:
- `Reflect.getCallerClass` is defined on JDK 17+ (the old
implementation always returned `None`; this is the directional test
that fails on the pre-PR code).
- `getCaller(0)` returns a non-null `Class` whose name starts with
`org.apache.pekko.util.Reflect`, validating the frame-skip
semantics.
- `getCaller(Int.MaxValue)` returns `null` for a depth beyond the
stack, matching the `findCaller` contract that filters `ne null`.
- `Reflect.findClassLoader()` returns a non-null `ClassLoader` for
the end-to-end path.
Result:
StackWalker migration is now protected by a directional test that
would fail on the pre-PR implementation.
Tests:
sbt "actor-tests/Test/testOnly org.apache.pekko.util.ReflectSpec" --
10/10 passed (4 new + 6 pre-existing findConstructor tests).
References:
Discovered during internal review of PR #3151.
…ng.StackWalker Motivation: Code review feedback to simplify the code by importing StackWalker instead of using fully-qualified java.lang.StackWalker references. Modification: Add import for java.lang.StackWalker and replace all fully-qualified references with the short name. Result: Cleaner, more readable code with standard Scala import conventions. References: Refs #3151
He-Pin
force-pushed
the
refactor/reflect-stackwalker
branch
from
June 23, 2026 10:58
b7b2c83 to
ea8154d
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
Reflect.getCallerClassusessun.reflect.Reflection.getCallerClassvia reflection — a JDK 8 internal API that was moved tojdk.internal.reflect.Reflectionin JDK 9+. On JDK 17+ without--add-opensforjdk.internal.reflect, this always falls back toNone, making thefindClassLoaderfallback path dead code.Modification
Replace with
java.lang.StackWalker(JDK 9) withRETAIN_CLASS_REFERENCEoption — the official, supported API for accessing caller class information. The API contract is preserved: given a frame depth index, returns theClassat that depth (ornullif beyond stack).Result
StackWalkerwas already established in the codebase (LoggerClass.scala,TestKitUtils.scala)findClassLoaderfallback now works reliably on JDK 17+Tests
sbt "actor/compile"— passedReferences
Refs #3136