didi/DoKit · error · ReflectedException

Need a caller!

Error message

Need a caller!

What it means

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.

Source

Thrown at Android/dokit/src/main/java/com/didichuxing/doraemonkit/util/Reflector.java:104

            throw new ReflectedException("Oops!", e.getTargetException());
        } catch (Throwable e) {
            throw new ReflectedException("Oops!", e);
        }
    }
    
    protected Object checked(@Nullable Object caller) throws ReflectedException {
        if (caller == null || mType.isInstance(caller)) {
            return caller;
        }
        throw new ReflectedException("Caller [" + caller + "] is not a instance of type [" + mType + "]!");
    }
    
    protected void check(@Nullable Object caller, @Nullable Member member, @NonNull String name) throws ReflectedException {
        if (member == null) {
            throw new ReflectedException(name + " was null!");
        }
        if (caller == null && !Modifier.isStatic(member.getModifiers())) {
            throw new ReflectedException("Need a caller!");
        }
        checked(caller);
    }
    
    public Reflector bind(@Nullable Object caller) throws ReflectedException {
        mCaller = checked(caller);
        return this;
    }
    
    public Reflector unbind() {
        mCaller = null;
        return this;
    }
    
    public Reflector field(@NonNull String name) throws ReflectedException {
        try {
            mField = findField(name);
            mField.setAccessible(true);

View on GitHub (pinned to 626827cddb)

Solutions

  1. Pass a real instance: use Reflector.with(instance) or callByCaller(realInstance, args)
  2. If the member should be static, verify with Modifier.isStatic(member.getModifiers()) — maybe the wrong overload/signature resolved to an instance member
  3. Null-check the caller object before invoking when it comes from another reflective call

Example fix

// before
Reflector.on(Activity.class).method("getApplication").call(); // instance method, no caller

// after
Application app = Reflector.with(activity).method("getApplication").call();
Defensive patterns

Strategy: validation

Validate before calling

if (caller == null && !Modifier.isStatic(member.getModifiers())) {
    // bind an instance first
    Reflector.with(instance);
}

Type guard

static boolean canCallWithoutCaller(java.lang.reflect.Member m) {
    return Modifier.isStatic(m.getModifiers());
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of didi/DoKit@626827cddb (2026-08-14). Data as JSON: /api/errors/41715f904691b005. Report an issue: GitHub.