spring-projects/spring-framework · error · IllegalArgumentException

DeclarePrecedence not presently supported in Spring AOP

Error message

DeclarePrecedence not presently supported in Spring AOP

What it means

Thrown as an IllegalArgumentException from the AspectMetadata constructor when ajType.getDeclarePrecedence() returns a non-empty array, i.e., the aspect declares precedence between other aspects (@DeclarePrecedence / declare-precedence). Spring AOP implements aspect ordering via the @Order annotation / Ordered interface instead, so it refuses aspects that use AspectJ's native declare-precedence mechanism.

Solutions

  1. Remove the @DeclarePrecedence annotation from the aspect.
  2. Express aspect ordering using @Order (or implementing Ordered) on each aspect bean, or via the 'order' attribute in XML config.
  3. If declare-precedence semantics are essential, use AspectJ compile-time or load-time weaving for those aspects.

Example fix

// before
import org.aspectj.lang.annotation.DeclarePrecedence;

@Aspect
@DeclarePrecedence("SecurityAspect, LoggingAspect, *")
public class OrderingAspect { ... }
// after
@Aspect
@Order(1)
public class SecurityAspect { ... }

@Aspect
@Order(2)
public class LoggingAspect { ... }
Defensive patterns

Strategy: validation

Validate before calling

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.AjTypeSystem;

public static boolean hasDeclarePrecedence(Class<?> aspectClass) {
    return AjTypeSystem.getAjType(aspectClass).getDeclarePrecedence().length > 0;
}

// before building advisors/metadata for the aspect:
if (hasDeclarePrecedence(MyAspect.class)) {
    throw new IllegalStateException("@DeclarePrecedence is not supported in Spring AOP; use @Order");
}

Type guard

import org.aspectj.lang.annotation.DeclarePrecedence;

public static boolean usesDeclarePrecedence(Class<?> c) {
    return c.getAnnotation(DeclarePrecedence.class) != null;
}

Try / catch

try {
    AspectMetadata md = new AspectMetadata(clazz, name);
} catch (IllegalArgumentException ex) {
    if (ex.getMessage().contains("DeclarePrecedence")) {
        // remove @DeclarePrecedence and use @Order-based ordering
    } else throw ex;
}

Prevention

When it happens

Trigger: An aspect class annotated with @DeclarePrecedence (org.aspectj.lang.annotation.DeclarePrecedence) being processed by Spring AOP auto-proxying or AspectMetadata construction; an aspect with a 'declare precedence' statement compiled by ajc and then exposed to Spring AOP.

Common situations: Porting an AspectJ-native aspect that orders other aspects via declare-precedence into Spring AOP; copying AspectJ ordering examples that Spring does not support.

Related errors


AI-assisted analysis of spring-projects/spring-framework@69bf83ad71 (2026-08-09). Data as JSON: /api/errors/1d772c2eb648c07e. Report an issue: GitHub.

Appendix: source

Thrown at spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AspectMetadata.java:98

	 */
	public AspectMetadata(Class<?> aspectClass, String aspectName) {
		this.aspectName = aspectName;

		Class<?> currClass = aspectClass;
		AjType<?> ajType = null;
		while (currClass != Object.class) {
			AjType<?> ajTypeToCheck = AjTypeSystem.getAjType(currClass);
			if (ajTypeToCheck.isAspect()) {
				ajType = ajTypeToCheck;
				break;
			}
			currClass = currClass.getSuperclass();
		}
		if (ajType == null) {
			throw new IllegalArgumentException("Class '" + aspectClass.getName() + "' is not an @AspectJ aspect");
		}
		if (ajType.getDeclarePrecedence().length > 0) {
			throw new IllegalArgumentException("DeclarePrecedence not presently supported in Spring AOP");
		}
		this.aspectClass = ajType.getJavaClass();
		this.ajType = ajType;

		switch (this.ajType.getPerClause().getKind()) {
			case SINGLETON -> {
				this.perClausePointcut = Pointcut.TRUE;
			}
			case PERTARGET, PERTHIS -> {
				AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut();
				ajexp.setLocation(aspectClass.getName());
				ajexp.setExpression(findPerClause(aspectClass));
				ajexp.setPointcutDeclarationScope(aspectClass);
				this.perClausePointcut = ajexp;
			}
			case PERTYPEWITHIN -> {
				// Works with a type pattern
				this.perClausePointcut = new ComposablePointcut(new TypePatternClassFilter(findPerClause(aspectClass)));

View on GitHub (pinned to 69bf83ad71)