{"id":"c70309fe063963dd","repo":"spring-projects/spring-framework","slug":"an-advice-method-can-never-be-a-constructor","errorCode":null,"errorMessage":"An advice method can never be a constructor","messagePattern":"An advice method can never be a constructor","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscoverer.java","lineNumber":290,"sourceCode":"\t\t\t\t\t\tthis.numberOfRemainingUnboundArguments + \" argument(s) could not be bound\");\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// convention for failing is to return null, allowing participation in a chain of responsibility\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * An advice method can never be a constructor in Spring.\n\t * @return {@code null}\n\t * @throws UnsupportedOperationException if\n\t * {@link #setRaiseExceptions(boolean) raiseExceptions} has been set to {@code true}\n\t */\n\t@Override\n\tpublic String @Nullable [] getParameterNames(Constructor<?> ctor) {\n\t\tif (this.raiseExceptions) {\n\t\t\tthrow new UnsupportedOperationException(\"An advice method can never be a constructor\");\n\t\t}\n\t\telse {\n\t\t\t// we return null rather than throw an exception so that we behave well\n\t\t\t// in a chain-of-responsibility.\n\t\t\treturn null;\n\t\t}\n\t}\n\n\n\tprivate void bindParameterName(int index, @Nullable String name) {\n\t\tthis.parameterNameBindings[index] = name;\n\t\tthis.numberOfRemainingUnboundArguments--;\n\t}\n\n\t/**\n\t * If the first parameter is of type JoinPoint or ProceedingJoinPoint, bind \"thisJoinPoint\" as\n\t * parameter name and return true, else return false.\n\t */","sourceCodeStart":272,"sourceCodeEnd":308,"githubUrl":"https://github.com/spring-projects/spring-framework/blob/e8729d043887bf0d0baf91e062e909b56eb2b708/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscoverer.java#L272-L308","documentation":"Thrown by AspectJAdviceParameterNameDiscoverer.getParameterNames(Constructor) (line 288-291) when raiseExceptions is true and a Constructor (rather than a Method) is passed. Advice is by definition a method, never a constructor, so the discoverer refuses to bind constructor parameters; normally it returns null to play nice in the chain-of-responsibility.","triggerScenarios":"A ParameterNameDiscoverer chain that includes this discoverer (with raiseExceptions=true) is asked for parameter names of a Constructor. This is unusual for advice wiring; it occurs when the same discoverer instance is reused generically to inspect constructors.","commonSituations":"Reusing the AspectJAdviceParameterNameDiscoverer outside its intended advice-wiring role (e.g. plugging it into a generic reflection utility that also queries constructors); misconfiguration passing a Constructor to a method-only discoverer.","solutions":["Do not reuse AspectJAdviceParameterNameDiscoverer for constructor introspection; use a standard discoverer (e.g. DefaultParameterNameDiscoverer) for constructors.","Leave raiseExceptions=false (the default for general use) so it returns null for constructors instead of throwing.","Scope the discoverer to advice method wiring only."],"exampleFix":"// before: reusing the advice discoverer to inspect a constructor\nAspectJAdviceParameterNameDiscoverer d = new AspectJAdviceParameterNameDiscoverer(pc);\nd.setRaiseExceptions(true);\nString[] names = d.getParameterNames(someConstructor);\n// after: use a standard discoverer for constructors\nString[] names = new DefaultParameterNameDiscoverer().getParameterNames(someConstructor);","handlingStrategy":"validation","validationCode":"// Do not use AspectJAdviceParameterNameDiscoverer for constructors.\nif (member instanceof Constructor<?>) {\n    throw new IllegalArgumentException(\n        \"Use DefaultParameterNameDiscoverer for constructors; AspectJAdviceParameterNameDiscoverer is method-only\");\n}","typeGuard":"private static boolean isAdviceMethodCandidate(Member m) {\n    return m instanceof Method;\n}","tryCatchPattern":null,"preventionTips":["Keep AspectJAdviceParameterNameDiscoverer scoped to advice method wiring only.","Use DefaultParameterNameDiscoverer for generic (including constructor) parameter name lookups.","Leave raiseExceptions=false when the discoverer participates in a general chain."],"tags":["spring-aop","aspectj","argument-binding","misuse","reflection"],"analyzedSha":"e8729d043887bf0d0baf91e062e909b56eb2b708","analyzedAt":"2026-08-04T19:07:39.725Z","schemaVersion":2}