mybatis/mybatis-3 · error · PluginException

Could not find method on {} named {}. Cause: {}

Error message

Could not find method on {} named {}. Cause: {}

What it means

Plugin.getSignatureMap() resolves each @Signature with Class.getMethod(name, args) and throws PluginException when lookup fails. The signature must name a real public method with exact parameter types on the given target interface.

Source

Thrown at src/main/java/org/apache/ibatis/plugin/Plugin.java:81

    }
  }

  private static Map<Class<?>, Set<Method>> getSignatureMap(Interceptor interceptor) {
    Intercepts interceptsAnnotation = interceptor.getClass().getAnnotation(Intercepts.class);
    // issue #251
    if (interceptsAnnotation == null) {
      throw new PluginException(
          "No @Intercepts annotation was found in interceptor " + interceptor.getClass().getName());
    }
    Signature[] sigs = interceptsAnnotation.value();
    Map<Class<?>, Set<Method>> signatureMap = new HashMap<>();
    for (Signature sig : sigs) {
      Set<Method> methods = signatureMap.computeIfAbsent(sig.type(), k -> new HashSet<>());
      try {
        Method method = sig.type().getMethod(sig.method(), sig.args());
        methods.add(method);
      } catch (NoSuchMethodException e) {
        throw new PluginException("Could not find method on " + sig.type() + " named " + sig.method() + ". Cause: " + e,
            e);
      }
    }
    return signatureMap;
  }

  private static Class<?>[] getAllInterfaces(Class<?> type, Map<Class<?>, Set<Method>> signatureMap) {
    Set<Class<?>> interfaces = new HashSet<>();
    while (type != null) {
      for (Class<?> c : type.getInterfaces()) {
        if (signatureMap.containsKey(c)) {
          interfaces.add(c);
        }
      }
      type = type.getSuperclass();
    }
    return interfaces.toArray(new Class<?>[0]);
  }

View on GitHub (pinned to 008069adb1)

Solutions

  1. Cross-check the method name and full parameter list against the exact MyBatis version's interface source (Executor, ParameterHandler, ResultSetHandler, StatementHandler).
  2. After a MyBatis upgrade, review every @Signature for changed parameter lists (e.g. six-arg Executor.query).
  3. Use parameterized args to catch drift at compile time instead of hard-coded Class literals.

Example fix

// before
@Intercepts(@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class}))
// after
@Intercepts(@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class}))
Defensive patterns

Strategy: validation

Validate before calling

// startup self-check of signatures
for (Signature s : interceptor.getClass().getAnnotation(Intercepts.class).value()) {
  s.type().getMethod(s.method(), s.args()); // throws NoSuchMethodException early, with a clear message
}

Prevention

When it happens

Trigger: @Signature(type = StatementHandler.class, method = "prepared", args = {Connection.class}) — wrong name, wrong arg count, wrong arg types/order, or a method that only exists on a different target interface.

Common situations: Upgrading MyBatis across versions where target-interface method signatures changed (classic: Executor.query gained BoundSql/CacheKey overloads); typos in method names; assuming a method exists on StatementHandler when it is on ResultSetHandler.

Related errors


AI-assisted analysis of mybatis/mybatis-3@008069adb1 (2026-08-14). Data as JSON: /api/errors/ee4d26924de24e62. Report an issue: GitHub.