didi/DoKit · error · ReflectedException
Oops!
Error message
Oops!
What it means
Reflector.on(String, boolean, ClassLoader) wraps Class.forName in a try-catch and rethrows any failure as ReflectedException("Oops!", e). The 'Oops!' message is generic; the real cause (usually ClassNotFoundException, or an initialization failure from the static initializer when initialize=true) is attached as the cause. This entry point is how DoraemonKit reflectively loads framework internals that vary across Android OS versions or vendor ROMs.
Source
Thrown at Android/dokit/src/main/java/com/didichuxing/doraemonkit/util/Reflector.java:48
}
public ReflectedException(String message, Throwable cause) {
super(message, cause);
}
}
public static Reflector on(@NonNull String name) throws ReflectedException {
return on(name, true, Reflector.class.getClassLoader());
}
public static Reflector on(@NonNull String name, boolean initialize) throws ReflectedException {
return on(name, initialize, Reflector.class.getClassLoader());
}
public static Reflector on(@NonNull String name, boolean initialize, @Nullable ClassLoader loader) throws ReflectedException {
try {
return on(Class.forName(name, initialize, loader));
} catch (Throwable e) {
throw new ReflectedException("Oops!", e);
}
}
public static Reflector on(@NonNull Class<?> type) {
Reflector reflector = new Reflector();
reflector.mType = type;
return reflector;
}
public static Reflector with(@NonNull Object caller) throws ReflectedException {
return on(caller.getClass()).bind(caller);
}
protected Reflector() {
}
public Reflector constructor(@Nullable Class<?>... parameterTypes) throws ReflectedException {View on GitHub (pinned to 626827cddb)
Solutions
- Read the attached cause: ClassNotFoundException means the name is wrong for this OS version — guard the call per Build.VERSION.SDK_INT
- Pass initialize=false if the class's static initializer is what fails
- Verify the fully-qualified class name against the AOSP source for the device's API level
- Switch to QuietReflector.on(...) which swallows the failure and exposes mIgnored instead of throwing
- If obfuscation renamed the target, add proguard keep rules for the reflected class
Example fix
// before
Reflector refl = Reflector.on("android.app.ActivityThread");
// after
if (Build.VERSION.SDK_INT >= 29) {
Reflector refl = Reflector.on("android.app.ActivityThread", false);
} else {
Reflector.QuietReflector refl = Reflector.QuietReflector.on("android.app.ActivityThread");
// refl.mIgnored != null -> feature unavailable on this device
} Defensive patterns
Strategy: try-catch
Validate before calling
public static boolean classExists(String fqcn, ClassLoader cl) {
try {
Class.forName(fqcn, false, cl != null ? cl : Reflector.class.getClassLoader());
return true;
} catch (Throwable t) {
return false;
}
} Try / catch
try {
Reflector r = Reflector.on("android.app.ActivityThread");
} catch (ReflectedException e) {
Throwable cause = e.getCause(); // usually ClassNotFoundException
if (cause instanceof ClassNotFoundException) { /* feature unavailable on this build */ }
} Prevention
- Gate reflective class lookups by Build.VERSION.SDK_INT
- Prefer QuietReflector for OS-internal classes
- Add proguard keep rules for reflectively accessed classes
When it happens
Trigger: Calling Reflector.on("android.some.InternalClass") when the class does not exist on the running device (removed/renamed in that API level), when the class is not visible to the supplied ClassLoader, or when initialize=true and the class's static initializer throws.
Common situations: Running DoraemonKit on an Android version whose hidden framework classes were refactored; vendor ROMs that strip internals; proguard/R8 renaming obfuscating the target class name; wrong ClassLoader in plugin/embedded environments.
Related errors
- reflect failed.
- leakTraceAsFakeException() can only be called when leakFound
- buildAndInstall() should only be called once.
- maxStoredHeapDumps must be at least 1
- Could not find char array in {}
AI-assisted analysis of didi/DoKit@626827cddb (2026-08-14).
Data as JSON: /api/errors/aff7cba7205bac9a.
Report an issue: GitHub.