{"record":{"id":"b84592301b903ebd","repo":"spring-projects/spring-framework","slug":"aspectclass-getname-uses-percflow-instantiatio","errorCode":null,"errorMessage":"{aspectClass.getName()} uses percflow instantiation model: This is not supported in Spring AOP.","messagePattern":"(.+?) uses percflow instantiation model: This is not supported in Spring AOP\\.","errorType":"exception","errorClass":"AopConfigException","httpStatus":null,"severity":"error","filePath":"spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AbstractAspectJAdvisorFactory.java","lineNumber":100,"sourceCode":"\tprotected final Log logger = LogFactory.getLog(getClass());\n\n\tprotected final ParameterNameDiscoverer parameterNameDiscoverer = new AspectJAnnotationParameterNameDiscoverer();\n\n\n\t@Override\n\tpublic boolean isAspect(Class<?> clazz) {\n\t\treturn (AnnotationUtils.findAnnotation(clazz, Aspect.class) != null &&\n\t\t\t\t(!shouldIgnoreAjcCompiledAspects || !compiledByAjc(clazz)));\n\t}\n\n\t@Override\n\tpublic void validate(Class<?> aspectClass) throws AopConfigException {\n\t\tAjType<?> ajType = AjTypeSystem.getAjType(aspectClass);\n\t\tif (!ajType.isAspect()) {\n\t\t\tthrow new NotAnAtAspectException(aspectClass);\n\t\t}\n\t\tif (ajType.getPerClause().getKind() == PerClauseKind.PERCFLOW) {\n\t\t\tthrow new AopConfigException(aspectClass.getName() + \" uses percflow instantiation model: \" +\n\t\t\t\t\t\"This is not supported in Spring AOP.\");\n\t\t}\n\t\tif (ajType.getPerClause().getKind() == PerClauseKind.PERCFLOWBELOW) {\n\t\t\tthrow new AopConfigException(aspectClass.getName() + \" uses percflowbelow instantiation model: \" +\n\t\t\t\t\t\"This is not supported in Spring AOP.\");\n\t\t}\n\t}\n\n\n\t/**\n\t * Find and return the first AspectJ annotation on the given method\n\t * (there <i>should</i> only be one anyway...).\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tprotected static @Nullable AspectJAnnotation findAspectJAnnotationOnMethod(Method method) {\n\t\tfor (Class<?> annotationType : ASPECTJ_ANNOTATION_CLASSES) {\n\t\t\tAspectJAnnotation annotation = findAnnotation(method, (Class<Annotation>) annotationType);\n\t\t\tif (annotation != null) {","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/spring-projects/spring-framework/blob/69bf83ad716d0cfc4b0520a19b4d8b24c79d1538/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AbstractAspectJAdvisorFactory.java#L82-L118","documentation":"Thrown by AbstractAspectJAdvisorFactory.validate() as an AopConfigException when the aspect's per-clause kind is PerClauseKind.PERCFLOW. Spring AOP's proxy-based model only supports singleton, perthis, pertarget, and pertypewithin instantiation; percflow (one aspect instance per flow/control-flow entry) requires load-time or compile-time AspectJ weaving and cannot be implemented with proxies. This check rejects such aspects early before advisor construction.","triggerScenarios":"Annotating a class with @Aspect(\"percflow(pointcut)\") and submitting it to Spring AOP via @EnableAspectJAutoProxy, AspectJProxyFactory.addAspect(...), or a BeanFactoryAspectJAdvisorsBuilder; calling advisorFactory.validate(aspectClass) on such a class.","commonSituations":"Porting an AspectJ aspect written for native AspectJ weaving into a Spring AOP application without changing the per-clause; copy-pasting an aspect from an AspectJ tutorial that uses percflow; upgrading a project where previously only AspectJ weaving was used and now @EnableAspectJAutoProxy is also active.","solutions":["Change the aspect instantiation model to singleton by removing the percflow value: use plain @Aspect (equivalent to @Aspect(\"singleton(...)\")).","If per-execution-flow scoping is genuinely required, switch to AspectJ compile-time (ajc) or load-time weaving instead of Spring AOP proxying.","If you need per-call state, simulate it with a ThreadLocal field inside a singleton aspect."],"exampleFix":"// before\n@Aspect(\"percflow(execution(* com.example.Service.*(..)))\")\npublic class FlowAspect { ... }\n// after\n@Aspect\npublic class FlowAspect {\n    private final ThreadLocal<Deque<Object>> flowState = new ThreadLocal<>();\n    ...\n}","handlingStrategy":"validation","validationCode":"import org.aspectj.lang.annotation.Aspect;\nimport org.aspectj.lang.reflect.AjTypeSystem;\nimport org.aspectj.lang.reflect.PerClauseKind;\n\npublic static boolean isSpringAopCompatible(Class<?> aspectClass) {\n    var kind = AjTypeSystem.getAjType(aspectClass).getPerClause().getKind();\n    return kind != PerClauseKind.PERCFLOW && kind != PerClauseKind.PERCFLOWBELOW;\n}\n\nif (!isSpringAopCompatible(MyAspect.class)) {\n    throw new IllegalStateException(\"Aspect uses an unsupported per-clause for Spring AOP\");\n}","typeGuard":"import org.aspectj.lang.reflect.AjTypeSystem;\nimport org.aspectj.lang.reflect.PerClauseKind;\n\npublic static boolean isPercflow(Class<?> c) {\n    return AjTypeSystem.getAjType(c).getPerClause().getKind() == PerClauseKind.PERCFLOW;\n}","tryCatchPattern":"try {\n    advisorFactory.validate(aspectClass);\n} catch (AopConfigException ex) {\n    if (ex.getMessage().contains(\"percflow\")) {\n        // rewrite the aspect or switch to AspectJ weaving\n    } else throw ex;\n}","preventionTips":["Avoid @Aspect(\"percflow(...)\") and @Aspect(\"percflowbelow(...)\") in Spring AOP projects.","Document which per-clauses Spring AOP supports (singleton, perthis, pertarget, pertypewithin) in a project ADR.","When importing aspects from AspectJ-native projects, audit their per-clauses."],"tags":["spring-aop","aspectj","instantiation-model","configuration"],"backgroundTag":null,"analyzedSha":"69bf83ad716d0cfc4b0520a19b4d8b24c79d1538","analyzedAt":"2026-08-09T15:32:58.770Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}