{"record":{"id":"41715f904691b005","repo":"didi/DoKit","slug":"need-a-caller","errorCode":null,"errorMessage":"Need a caller!","messagePattern":"Need a caller!","errorType":"validation","errorClass":"ReflectedException","httpStatus":null,"severity":"error","filePath":"Android/dokit/src/main/java/com/didichuxing/doraemonkit/util/Reflector.java","lineNumber":104,"sourceCode":"            throw new ReflectedException(\"Oops!\", e.getTargetException());\n        } catch (Throwable e) {\n            throw new ReflectedException(\"Oops!\", e);\n        }\n    }\n    \n    protected Object checked(@Nullable Object caller) throws ReflectedException {\n        if (caller == null || mType.isInstance(caller)) {\n            return caller;\n        }\n        throw new ReflectedException(\"Caller [\" + caller + \"] is not a instance of type [\" + mType + \"]!\");\n    }\n    \n    protected void check(@Nullable Object caller, @Nullable Member member, @NonNull String name) throws ReflectedException {\n        if (member == null) {\n            throw new ReflectedException(name + \" was null!\");\n        }\n        if (caller == null && !Modifier.isStatic(member.getModifiers())) {\n            throw new ReflectedException(\"Need a caller!\");\n        }\n        checked(caller);\n    }\n    \n    public Reflector bind(@Nullable Object caller) throws ReflectedException {\n        mCaller = checked(caller);\n        return this;\n    }\n    \n    public Reflector unbind() {\n        mCaller = null;\n        return this;\n    }\n    \n    public Reflector field(@NonNull String name) throws ReflectedException {\n        try {\n            mField = findField(name);\n            mField.setAccessible(true);","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/didi/DoKit/blob/626827cddb2feb2f3aee87a52a064b4e5ca2bed4/Android/dokit/src/main/java/com/didichuxing/doraemonkit/util/Reflector.java#L86-L122","documentation":"Reflector.check throws 'Need a caller!' when the resolved member is an INSTANCE member but caller is null. Reflection cannot invoke a non-static Field.get/Method.invoke on a null receiver, so the guard fails fast with an explicit message instead of the JVM's ambiguous NullPointerException.","triggerScenarios":"Calling callByCaller(null, args) or get(null) on an instance method/field; using Reflector.on(SomeClass.class).method(\"instanceMethod\").call() without binding an instance via bind()/with(); the mCaller was unbound() before the call.","commonSituations":"Static-looking helper methods that are actually instance methods in that OS version; forgetting .with(instance) after on(class); a null object obtained from a prior failed reflective get being passed as caller.","solutions":["Pass a real instance: use Reflector.with(instance) or callByCaller(realInstance, args)","If the member should be static, verify with Modifier.isStatic(member.getModifiers()) — maybe the wrong overload/signature resolved to an instance member","Null-check the caller object before invoking when it comes from another reflective call"],"exampleFix":"// before\nReflector.on(Activity.class).method(\"getApplication\").call(); // instance method, no caller\n\n// after\nApplication app = Reflector.with(activity).method(\"getApplication\").call();","handlingStrategy":"validation","validationCode":"if (caller == null && !Modifier.isStatic(member.getModifiers())) {\n    // bind an instance first\n    Reflector.with(instance);\n}","typeGuard":"static boolean canCallWithoutCaller(java.lang.reflect.Member m) {\n    return Modifier.isStatic(m.getModifiers());\n}","tryCatchPattern":null,"preventionTips":["Use Reflector.with(instance) for instance members, Reflector.on(class) only for static ones","Null-check objects returned from earlier reflective calls before using them as callers"],"tags":["reflection","null-caller","instance-method","api-misuse"],"backgroundTag":null,"analyzedSha":"626827cddb2feb2f3aee87a52a064b4e5ca2bed4","analyzedAt":"2026-08-14T12:45:58.758Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}