spring-projects/spring-framework · error · UnsupportedOperationException

Illegal MethodMatcher usage

Error message

Illegal MethodMatcher usage

What it means

StaticMethodMatcher is a convenience base for pointcut matchers that only decide matches at registration time, so isRuntime() is hard-wired to false and the 3-arg matches(Method, Class, Object...) is declared final and throws UnsupportedOperationException. Spring's own AOP runtime always consults isRuntime() before invoking the 3-arg form, so this exception means the 3-arg method was called despite the matcher being static. In practice it signals custom code, a test, or a misbehaving advisor that bypassed the isRuntime() guard.

Source

Thrown at spring-aop/src/main/java/org/springframework/aop/support/StaticMethodMatcher.java:41

import org.springframework.aop.MethodMatcher;

/**
 * Convenient abstract superclass for static method matchers, which don't care
 * about arguments at runtime.
 *
 * @author Rod Johnson
 */
public abstract class StaticMethodMatcher implements MethodMatcher {

	@Override
	public final boolean isRuntime() {
		return false;
	}

	@Override
	public final boolean matches(Method method, Class<?> targetClass, @Nullable Object... args) {
		// should never be invoked because isRuntime() returns false
		throw new UnsupportedOperationException("Illegal MethodMatcher usage");
	}

}

View on GitHub (pinned to e8729d0438)

Solutions

  1. Check matcher.isRuntime() before invoking the 3-arg matches(); only call it for DynamicMethodMatcher instances.
  2. For static matchers use the 2-arg form matches(method, targetClass) which is the method subclasses actually implement.
  3. If you genuinely need runtime argument matching, extend DynamicMethodMatcher (or implement MethodMatcher directly) instead of StaticMethodMatcher.

Example fix

// before
boolean hit = pointcut.getMethodMatcher().matches(method, beanClass, args);

// after
MethodMatcher mm = pointcut.getMethodMatcher();
boolean hit = mm.isRuntime()
    ? mm.matches(method, beanClass, args)
    : mm.matches(method, beanClass);
Defensive patterns

Strategy: type-guard

Validate before calling

MethodMatcher mm = pointcut.getMethodMatcher();
if (mm.isRuntime()) {
    // safe to call the 3-arg form
    mm.matches(method, beanClass, args);
} else {
    // static matcher: use the 2-arg form only
    mm.matches(method, beanClass);
}

Type guard

static boolean isStaticMatcher(MethodMatcher mm) { return !mm.isRuntime(); }

Try / catch

try {
    boolean hit = mm.matches(method, beanClass, args);
} catch (UnsupportedOperationException ex) {
    if ("Illegal MethodMatcher usage".equals(ex.getMessage())) {
        // fall back to 2-arg static matching
        hit = mm.matches(method, beanClass);
    } else throw ex;
}

Prevention

When it happens

Trigger: Calling matcher.matches(method, targetClass, args) directly on an instance of a StaticMethodMatcher subclass; a custom PointcutAdvisor/Interceptor/IntroductionAdvice that invokes the 3-arg matches() without first checking matcher.isRuntime(); a unit test exercising argument matching on a static matcher.

Common situations: Writing custom AOP utilities or reflection-based pointcut testers; integrating a third-party library that assumes all MethodMatchers are dynamic; upgrading Spring where the 3-arg matches() on StaticMethodMatcher became final and previously-overridden code now hits the superclass.

Related errors


AI-assisted analysis of spring-projects/spring-framework@e8729d0438 (2026-08-04). Data as JSON: /data/errors/1ea0391185cb5402.json. Report an issue: GitHub.