fix: how to call static method of class - #2
Conversation
Previously, calling static methods via `call().get()` threw an exception unless `create()` was used, forcing class instantiation. Updated `OkReflect` to bypass `create()` for static invocations, enabling direct static method execution without object creation. Closes zeshaoaaa#1. Patch generated by qwen3.6-35b-a3b via local API.
|
@webbrain-one, ⭐3 XP earned, 🏆First Pull Request Pushed completed, 💪Level 1 achieved! |
📝 WalkthroughWalkthroughOkReflect adds a ChangesStatic member support
Estimated code review effort: 2 (Simple) | ~10 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/main/kotlin/okreflect/OkReflect.kt`:
- Around line 238-247: Update the static-mode flow around `OkReflect.static()`
and `realGet()` so the target class is always initialized via `initClazz()`
before static method or field lookup, while still skipping instance
construction. Preserve the existing behavior for both
`OkReflect.on(Class).static()` and `OkReflect.on(String).static()`, and add
regression coverage for each entry path.
- Around line 242-245: Add a Java-safe alias such as staticMembers() alongside
OkReflect.`static`() that selects the same static mode by reusing the existing
implementation, and extend the Java-facing tests to invoke and verify the alias.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 2601081b-2247-4375-aec5-1072b0cd35bd
📒 Files selected for processing (1)
src/main/kotlin/okreflect/OkReflect.kt
| /** | ||
| * Marks the current OkReflect instance to operate on static members. | ||
| * No instance will be created, allowing calls to static methods/fields. | ||
| */ | ||
| fun `static`(): OkReflect { | ||
| withOuterInstance = true | ||
| instance = null | ||
| return this | ||
| } | ||
|
|
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
# Expect: static mode initializes clazz before getMethod() is called.
rg -n -C 8 \
'fun `static`\(|private fun realGet|private fun initClazz|\bgetMethod\s*\(' \
src/main/kotlin src/testRepository: zeshaoaaa/OkReflect
Length of output: 7485
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
echo "== OkReflect.kt core sections =="
sed -n '1,140p' src/main/kotlin/okreflect/OkReflect.kt
echo
sed -n '220,280p' src/main/kotlin/okreflect/OkReflect.kt
echo
sed -n '300,385p' src/main/kotlin/okreflect/OkReflect.kt
echo
sed -n '520,590p' src/main/kotlin/okreflect/OkReflect.kt
echo
echo "== Static usage / tests =="
rg -n -C 4 'static\(\)|\.on\("(?:[^"]*|[^"]*)")|static method|getMethod\(' src/test src/main/kotlin || trueRepository: zeshaoaaa/OkReflect
Length of output: 10702
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
echo "== OkReflect static API declarations =="
rg -n -C 5 'on\s*\(|fun on\s*\(|companion|object' src/main/kotlin/okreflect/OkReflect.kt
echo
echo "== MethodGetter implementation =="
sed -n '1,170p' src/main/kotlin/okreflect/MethodGetter.kt
echo
echo "== Static usage/tests =="
rg -n -C 4 'static\(\)|`static`\(' src/test src/main/kotlin || true
rg -n -C 3 'on\(".*"\)' src/test src/main/kotlin || true
echo
echo "== Read-only Kotlin flow probe =="
python3 - <<'PY'
from pathlib import Path
p = Path("src/main/kotlin/okreflect/OkReflect.kt")
s = p.read_text()
checks = {
"String constructor sets className": "constructor(className: String)\n this.className = className" in s,
"static sets withOuterInstance true": "fun `static`():" in s and "withOuterInstance = true" in s.split("fun `static`()")[1].split("fun with")[0],
"realGet skips initClazz when withOuterInstance": "if (!withOuterInstance) {" in s and "initClazz()" in s.split("if (!withOuterInstance) {",1)[0],
"invoke passes current clazz to getMethod": 'getMethod(clazz, methodCall.classes' in s,
"initClazz initializes clazz from className": "private fun initClazz()\n if (clazz == null) {\n this.clazz = Class.forName(className!!)" in s,
}
for k, v in checks.items():
print(f"{k}: {v}")
PYRepository: zeshaoaaa/OkReflect
Length of output: 26518
Load clazz before invoking static methods.
OkReflect.on(String) sets only className, so clazz is null. In static mode, realGet() skips initClazz() and passes null to getMethod(), which fails before the reflection call. Keep class loading enabled for the static path, or use a separate static-mode flag that bypasses construction but not class initialization. Add regression tests for both OkReflect.on(Class).static()) and OkReflect.on(String).static().
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/main/kotlin/okreflect/OkReflect.kt` around lines 238 - 247, Update the
static-mode flow around `OkReflect.static()` and `realGet()` so the target class
is always initialized via `initClazz()` before static method or field lookup,
while still skipping instance construction. Preserve the existing behavior for
both `OkReflect.on(Class).static()` and `OkReflect.on(String).static()`, and add
regression coverage for each entry path.
| fun `static`(): OkReflect { | ||
| withOuterInstance = true | ||
| instance = null | ||
| return this |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
# Expect: a Java-safe alias or JVM-name mapping for static mode.
rg -n -C 5 \
'fun `static`\(|`@JvmName`|staticMembers|\.static\(\)' \
src/main/kotlin src/testRepository: zeshaoaaa/OkReflect
Length of output: 921
🏁 Script executed:
#!/usr/bin/env/bash
set -euo pipefail
echo "== OkReflect.kt relevant declarations =="
wc -l src/main/kotlin/okreflect/OkReflect.kt
sed -n '1,90p' src/main/kotlin/okreflect/OkReflect.kt
sed -n '220,255p' src/main/kotlin/okreflect/OkReflect.kt
echo "== build config =="
fd -a 'gradle|build\.kts|settings\.gradle|pom\.xml|build\.gradle' . | sed 's#^\./##'
echo "== Java static tests/usages =="
rg -n -C 3 'OkReflect|\.static\(|withOuterInstance|staticMembers|`@JvmName`' src/test src/main/kotlin/okreflect || true
echo "== Java reserved keyword and Kotlin backticked identifier probe =="
python3 - <<'PY'
import pathlib, re
files = list(map(pathlib.Path, pathlib.Path('.').rglob('*')))
text = '\n'.join(str(p) for p in files)
print("sample of OkReflect.kt:", pathlib.Path('src/main/kotlin/okreflect/OkReflect.kt').read_text()[:1200])
PY
# Read-only: demonstrate Java source cannot treat static as an identifier token in a valid type-qualified method call expression.
printf 'valid Java identifiers from reserved words: null, true, false\n'
tmp="$(mktemp -d)"
printf 'package p; class X { void f() { p.OkReflect.static().toString(); } }\n' > "$tmp/X.java"
javac -d "$tmp" "$tmp/X.java" 2>&1 || true
javac -version 2>&1 | sed -n '1p'
rm -rf "$tmp"Repository: zeshaoaaa/OkReflect
Length of output: 50377
🏁 Script executed:
#!/usr/bin/env/bash
set -euo pipefail
echo "== OkReflect.kt relevant declarations =="
wc -l src/main/kotlin/okreflect/OkReflect.kt
sed -n '1,90p' src/main/kotlin/okreflect/OkReflect.kt
sed -n '220,255p' src/main/kotlin/okreflect/OkReflect.kt
echo "== build config =="
fd -a 'gradle|build\.kts|settings\.gradle|pom\.xml|build\.gradle' . | sed 's#^\./##'
echo "== Java static tests/usages =="
rg -n -C 3 'OkReflect|\.static\(|withOuterInstance|staticMembers|`@JvmName`' src/test src/main/kotlin/okreflect || true
echo "== Java reserved keyword and Kotlin backticked identifier probe =="
python3 - <<'PY'
import pathlib, re
files = list(map(pathlib.Path, pathlib.Path('.').rglob('*')))
print("sample of OkReflect.kt:", pathlib.Path('src/main/kotlin/okreflect/OkReflect.kt').read_text()[:1200])
PY
# Read-only: show Java source cannot treat static as an identifier token in a type-qualified method-call form.
printf 'valid Java identifiers from reserved words: null, true, false\n'
tmp="$(mktemp -d)"
printf 'package p; class X { void f() { p.OkReflect.static().toString(); } }\n' > "$tmp/X.java"
javac -d "$tmp" "$tmp/X.java" 2>&1 || true
javac -version 2>&1 | sed -n '1p'
rm -rf "$tmp"Repository: zeshaoaaa/OkReflect
Length of output: 50377
🌐 Web query:
Java compiler reserved word cannot be used as an identifier example static
💡 Result:
In Java, a reserved keyword cannot be used as an identifier [1][2]. Because 'static' is a reserved keyword in the Java programming language, attempting to use it as an identifier (for example, naming a variable, method, or class 'static') will result in a compile-time error [1][3][4]. The Java Language Specification (JLS) mandates that an identifier never have the same spelling as a reserved keyword, a boolean literal, or the null literal [1][2]. During tokenization, the compiler adheres to the "longest possible translation" rule; if a sequence of characters matches a reserved keyword, it is reduced to a keyword token rather than an identifier [1][5][2]. For example, if you attempt to write: int static = 10; // Compile-time error The compiler will reject this because 'static' is a reserved keyword and cannot function as a user-defined name [1][6]. While Java also includes "contextual keywords" (such as 'var' or 'yield') that can sometimes act as identifiers depending on where they appear, 'static' is a fully reserved keyword and is restricted in all contexts [1][7][2].
Citations:
- 1: https://docs.oracle.com/en/java/javase/26/docs/specs/jls/jls-3.html
- 2: https://docs.oracle.com/javase/specs/jls/se24/html/jls-3.html
- 3: https://stackoverflow.com/questions/423994/reserved-words-as-names-or-identifiers
- 4: https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html
- 5: https://docs.oracle.com/javase/specs/jls/se23/html/jls-3.html
- 6: https://en.wikipedia.org/wiki/List_of_Java_keywords
- 7: https://docs.oracle.com/javase/specs/jls/se16/preview/specs/contextual-keywords-jls.html
Expose a Java-callable name for static mode.
The JVM method generated for fun static() is named static, and Java source cannot call a member whose identifier spelling is the reserved static keyword. Add a Java-safe alias such as staticMembers() and cover it in the Java tests.
Possible compatibility fix
+ fun staticMembers(): OkReflect = `static`()📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| fun `static`(): OkReflect { | |
| withOuterInstance = true | |
| instance = null | |
| return this | |
| fun `static`(): OkReflect { | |
| withOuterInstance = true | |
| instance = null | |
| return this | |
| } | |
| fun staticMembers(): OkReflect = `static`() |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/main/kotlin/okreflect/OkReflect.kt` around lines 242 - 245, Add a
Java-safe alias such as staticMembers() alongside OkReflect.`static`() that
selects the same static mode by reusing the existing implementation, and extend
the Java-facing tests to invoke and verify the alias.
There was a problem hiding this comment.
4 issues found across 1 file
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="src/main/kotlin/okreflect/OkReflect.kt">
<violation number="1" location="src/main/kotlin/okreflect/OkReflect.kt:242">
P2: The new method is named `static` using Kotlin's backtick-escaped identifier syntax, but `static` is a reserved keyword in Java. Java callers will not be able to invoke this method using normal syntax (`okReflect.static()`), which breaks Java interop for consumers of this library. Consider adding a Java-callable alias such as `staticMembers()` that delegates to `static()`, and cover it with a Java-based test.</violation>
<violation number="2" location="src/main/kotlin/okreflect/OkReflect.kt:242">
P3: The new `static()` block was inserted between the KDoc for `with(...)` and the `with()` method body. As a result `with()` has lost its documentation (`@param instance ... pass the instance in this method` comment now sits detached above `static()`), and `static()` ended up with two consecutive Javadoc blocks — the first one actually describing `with()`. This misassociates the API docs. Recommend placing the entire new `static()` method and its own doc comment *before* the existing `with()` doc comment so each method keeps its matching documentation.</violation>
<violation number="3" location="src/main/kotlin/okreflect/OkReflect.kt:243">
P1: Static calls created with `on("fully.qualified.Class")` fail before invocation because static mode skips class initialization. Initialize `clazz` in `static()` before enabling outer-instance mode so both class-name and `Class` entry points work.</violation>
<violation number="4" location="src/main/kotlin/okreflect/OkReflect.kt:342">
P3: The new `targetObj` conditional is a no-op: in every case it evaluates to exactly `instance` (or `null` when `instance` is null). Concretely, when `instance == null` but `withOuterInstance` is false, the conditional falls through to `instance` (i.e. null); when `instance != null` it also returns `instance`. So `method.invoke(targetObj, *args)` behaves identically to the pre-change `method.invoke(instance, *args)`. The actual mechanism that makes static calls work in this PR is `static()` toggling `withOuterInstance = true`, which reroutes `realGet` into the `else` branch that skips constructor verification — the `targetObj` expression adds no behavior. Consider dropping the local and passing `instance` directly to avoid misleading logic that suggests it changes static vs. instance dispatch when it does not.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| * No instance will be created, allowing calls to static methods/fields. | ||
| */ | ||
| fun `static`(): OkReflect { | ||
| withOuterInstance = true |
There was a problem hiding this comment.
P1: Static calls created with on("fully.qualified.Class") fail before invocation because static mode skips class initialization. Initialize clazz in static() before enabling outer-instance mode so both class-name and Class entry points work.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/main/kotlin/okreflect/OkReflect.kt, line 243:
<comment>Static calls created with `on("fully.qualified.Class")` fail before invocation because static mode skips class initialization. Initialize `clazz` in `static()` before enabling outer-instance mode so both class-name and `Class` entry points work.</comment>
<file context>
@@ -235,6 +235,16 @@ open class OkReflect {
+ * No instance will be created, allowing calls to static methods/fields.
+ */
+ fun `static`(): OkReflect {
+ withOuterInstance = true
+ instance = null
+ return this
</file context>
| withOuterInstance = true | |
| if (clazz == null) initClazz() | |
| withOuterInstance = true |
| * Marks the current OkReflect instance to operate on static members. | ||
| * No instance will be created, allowing calls to static methods/fields. | ||
| */ | ||
| fun `static`(): OkReflect { |
There was a problem hiding this comment.
P2: The new method is named static using Kotlin's backtick-escaped identifier syntax, but static is a reserved keyword in Java. Java callers will not be able to invoke this method using normal syntax (okReflect.static()), which breaks Java interop for consumers of this library. Consider adding a Java-callable alias such as staticMembers() that delegates to static(), and cover it with a Java-based test.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/main/kotlin/okreflect/OkReflect.kt, line 242:
<comment>The new method is named `static` using Kotlin's backtick-escaped identifier syntax, but `static` is a reserved keyword in Java. Java callers will not be able to invoke this method using normal syntax (`okReflect.static()`), which breaks Java interop for consumers of this library. Consider adding a Java-callable alias such as `staticMembers()` that delegates to `static()`, and cover it with a Java-based test.</comment>
<file context>
@@ -235,6 +235,16 @@ open class OkReflect {
+ * Marks the current OkReflect instance to operate on static members.
+ * No instance will be created, allowing calls to static methods/fields.
+ */
+ fun `static`(): OkReflect {
+ withOuterInstance = true
+ instance = null
</file context>
| val args = methodCall.args | ||
| val method = getMethod(clazz, methodCall.classes, methodCall.methodName, args) | ||
| val returnType = method!!.returnType.toString() | ||
| val targetObj = if (withOuterInstance && instance == null) null else instance |
There was a problem hiding this comment.
P3: The new targetObj conditional is a no-op: in every case it evaluates to exactly instance (or null when instance is null). Concretely, when instance == null but withOuterInstance is false, the conditional falls through to instance (i.e. null); when instance != null it also returns instance. So method.invoke(targetObj, *args) behaves identically to the pre-change method.invoke(instance, *args). The actual mechanism that makes static calls work in this PR is static() toggling withOuterInstance = true, which reroutes realGet into the else branch that skips constructor verification — the targetObj expression adds no behavior. Consider dropping the local and passing instance directly to avoid misleading logic that suggests it changes static vs. instance dispatch when it does not.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/main/kotlin/okreflect/OkReflect.kt, line 342:
<comment>The new `targetObj` conditional is a no-op: in every case it evaluates to exactly `instance` (or `null` when `instance` is null). Concretely, when `instance == null` but `withOuterInstance` is false, the conditional falls through to `instance` (i.e. null); when `instance != null` it also returns `instance`. So `method.invoke(targetObj, *args)` behaves identically to the pre-change `method.invoke(instance, *args)`. The actual mechanism that makes static calls work in this PR is `static()` toggling `withOuterInstance = true`, which reroutes `realGet` into the `else` branch that skips constructor verification — the `targetObj` expression adds no behavior. Consider dropping the local and passing `instance` directly to avoid misleading logic that suggests it changes static vs. instance dispatch when it does not.</comment>
<file context>
@@ -329,11 +339,12 @@ open class OkReflect {
val args = methodCall.args
val method = getMethod(clazz, methodCall.classes, methodCall.methodName, args)
val returnType = method!!.returnType.toString()
+ val targetObj = if (withOuterInstance && instance == null) null else instance
if (returnType == "void") {
- method.invoke(instance, *args)
</file context>
| * Marks the current OkReflect instance to operate on static members. | ||
| * No instance will be created, allowing calls to static methods/fields. | ||
| */ | ||
| fun `static`(): OkReflect { |
There was a problem hiding this comment.
P3: The new static() block was inserted between the KDoc for with(...) and the with() method body. As a result with() has lost its documentation (@param instance ... pass the instance in this method comment now sits detached above static()), and static() ended up with two consecutive Javadoc blocks — the first one actually describing with(). This misassociates the API docs. Recommend placing the entire new static() method and its own doc comment before the existing with() doc comment so each method keeps its matching documentation.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/main/kotlin/okreflect/OkReflect.kt, line 242:
<comment>The new `static()` block was inserted between the KDoc for `with(...)` and the `with()` method body. As a result `with()` has lost its documentation (`@param instance ... pass the instance in this method` comment now sits detached above `static()`), and `static()` ended up with two consecutive Javadoc blocks — the first one actually describing `with()`. This misassociates the API docs. Recommend placing the entire new `static()` method and its own doc comment *before* the existing `with()` doc comment so each method keeps its matching documentation.</comment>
<file context>
@@ -235,6 +235,16 @@ open class OkReflect {
+ * Marks the current OkReflect instance to operate on static members.
+ * No instance will be created, allowing calls to static methods/fields.
+ */
+ fun `static`(): OkReflect {
+ withOuterInstance = true
+ instance = null
</file context>
Closes #1
Patch generated by
qwen3.6-35b-a3b via local API.Summary by cubic
Allow calling static methods in
OkReflectwithout creating an instance by addingstatic()and routing calls with a null target. Fixes exceptions incall().get()for static methods; closes #1.static()to operate on static methods/fields withoutcreate().nulltarget when marked static to prevent errors.Written for commit b1e5796. Summary will update on new commits.
Summary by CodeRabbit