{"record":{"id":"1a1be605e345f924","repo":"spring-projects/spring-framework","slug":"perclause-ajtype-getperclause-getkind-not-su","errorCode":null,"errorMessage":"PerClause {ajType.getPerClause().getKind()} not supported by Spring AOP for {aspectClass}","messagePattern":"PerClause (.+?) not supported by Spring AOP for (.+?)","errorType":"exception","errorClass":"AopConfigException","httpStatus":null,"severity":"error","filePath":"spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AspectMetadata.java","lineNumber":118,"sourceCode":"\t\tthis.aspectClass = ajType.getJavaClass();\n\t\tthis.ajType = ajType;\n\n\t\tswitch (this.ajType.getPerClause().getKind()) {\n\t\t\tcase SINGLETON -> {\n\t\t\t\tthis.perClausePointcut = Pointcut.TRUE;\n\t\t\t}\n\t\t\tcase PERTARGET, PERTHIS -> {\n\t\t\t\tAspectJExpressionPointcut ajexp = new AspectJExpressionPointcut();\n\t\t\t\tajexp.setLocation(aspectClass.getName());\n\t\t\t\tajexp.setExpression(findPerClause(aspectClass));\n\t\t\t\tajexp.setPointcutDeclarationScope(aspectClass);\n\t\t\t\tthis.perClausePointcut = ajexp;\n\t\t\t}\n\t\t\tcase PERTYPEWITHIN -> {\n\t\t\t\t// Works with a type pattern\n\t\t\t\tthis.perClausePointcut = new ComposablePointcut(new TypePatternClassFilter(findPerClause(aspectClass)));\n\t\t\t}\n\t\t\tdefault -> throw new AopConfigException(\n\t\t\t\t\t\"PerClause \" + ajType.getPerClause().getKind() + \" not supported by Spring AOP for \" + aspectClass);\n\t\t}\n\t}\n\n\t/**\n\t * Extract contents from String of form {@code pertarget(contents)}.\n\t */\n\tprivate String findPerClause(Class<?> aspectClass) {\n\t\tAspect ann = aspectClass.getAnnotation(Aspect.class);\n\t\tif (ann == null) {\n\t\t\treturn \"\";\n\t\t}\n\t\tString value = ann.value();\n\t\tint beginIndex = value.indexOf('(');\n\t\tif (beginIndex < 0) {\n\t\t\treturn \"\";\n\t\t}\n\t\treturn value.substring(beginIndex + 1, value.length() - 1);","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/spring-projects/spring-framework/blob/69bf83ad716d0cfc4b0520a19b4d8b24c79d1538/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AspectMetadata.java#L100-L136","documentation":"Thrown as an AopConfigException from the AspectMetadata constructor's switch default branch when the per-clause kind is not SINGLETON, PERTARGET, PERTHIS, or PERTYPEWITHIN. The remaining AspectJ per-clause kinds are PERCFLOW and PERCFLOWBELOW, which Spring AOP cannot implement with proxies. This is the metadata-layer companion to the AbstractAspectJAdvisorFactory.validate() checks (errors 41/42).","triggerScenarios":"Constructing AspectMetadata for a class annotated @Aspect(\"percflow(...)\") or @Aspect(\"percflowbelow(...)\"); indirectly when BeanFactoryAspectJAdvisorsBuilder or AspectJProxyFactory builds metadata for such a class.","commonSituations":"Using an AspectJ-native aspect with control-flow-scoped instantiation in a Spring AOP context; migrating from AspectJ weaving to Spring AOP without rewriting the per-clause.","solutions":["Switch the aspect to a singleton per-clause (plain @Aspect) or to perthis/pertarget/pertypewithin if Spring-supported per-object semantics are needed.","Use AspectJ compile-time or load-time weaving for aspects that genuinely require percflow/percflowbelow.","Simulate control-flow-scoped state with a ThreadLocal in a singleton aspect."],"exampleFix":"// before\n@Aspect(\"percflow(execution(* com.example.Service.*(..)))\")\npublic class FlowScopedAspect { ... }\n// after\n@Aspect\npublic class FlowScopedAspect {\n    private final ThreadLocal<Integer> depth = ThreadLocal.withInitial(() -> 0);\n    @Around(\"execution(* com.example.Service.*(..))\")\n    public Object track(ProceedingJoinPoint pjp) throws Throwable { ... }\n}","handlingStrategy":"validation","validationCode":"import org.aspectj.lang.reflect.AjTypeSystem;\nimport org.aspectj.lang.reflect.PerClauseKind;\nimport java.util.EnumSet;\n\npublic static boolean isSupportedPerClause(Class<?> aspectClass) {\n    var kind = AjTypeSystem.getAjType(aspectClass).getPerClause().getKind();\n    return EnumSet.of(PerClauseKind.SINGLETON, PerClauseKind.PERTARGET,\n                      PerClauseKind.PERTHIS, PerClauseKind.PERTYPEWITHIN).contains(kind);\n}\n\n// before new AspectMetadata(clazz, name):\nif (!isSupportedPerClause(clazz)) {\n    throw new IllegalStateException(\"Aspect per-clause not supported by Spring AOP: \" + clazz);\n}","typeGuard":"import org.aspectj.lang.reflect.AjTypeSystem;\nimport org.aspectj.lang.reflect.PerClauseKind;\n\npublic static boolean isSpringSupportedPerClause(Class<?> c) {\n    var k = AjTypeSystem.getAjType(c).getPerClause().getKind();\n    return k != PerClauseKind.PERCFLOW && k != PerClauseKind.PERCFLOWBELOW;\n}","tryCatchPattern":"try {\n    AspectMetadata md = new AspectMetadata(clazz, name);\n} catch (AopConfigException ex) {\n    if (ex.getMessage().contains(\"not supported by Spring AOP\")) {\n        // switch per-clause to singleton or use AspectJ weaving\n    } else throw ex;\n}","preventionTips":["Restrict aspect per-clauses to singleton/perthis/pertarget/pertypewithin in Spring AOP modules.","Route control-flow-scoped aspects to an AspectJ-weaving module.","Add a startup check listing each aspect's per-clause kind."],"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"}