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
- Remove the @DeclarePrecedence annotation from the aspect.
- Express aspect ordering using @Order (or implementing Ordered) on each aspect bean, or via the 'order' attribute in XML config.
- 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
- Use @Order / Ordered for aspect ordering in Spring AOP, never @DeclarePrecedence.
- Audit imported aspects for declare-precedence usage.
- Document ordering conventions in a project guide.
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
- Advice must be declared inside an aspect type: Offending…
- 'argumentNames' property of AbstractAspectJAdvice contains…
- is not an @AspectJ aspect
- uses percflow instantiation model: This is not supported in…
- uses percflowbelow instantiation model: This is not…
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)