spring-projects/spring-framework · error · UnsupportedOperationException

An advice method can never be a constructor

Error message

An advice method can never be a constructor

What it means

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.

Source

Thrown at spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscoverer.java:290

						this.numberOfRemainingUnboundArguments + " argument(s) could not be bound");
			}
			else {
				// convention for failing is to return null, allowing participation in a chain of responsibility
				return null;
			}
		}
	}

	/**
	 * An advice method can never be a constructor in Spring.
	 * @return {@code null}
	 * @throws UnsupportedOperationException if
	 * {@link #setRaiseExceptions(boolean) raiseExceptions} has been set to {@code true}
	 */
	@Override
	public String @Nullable [] getParameterNames(Constructor<?> ctor) {
		if (this.raiseExceptions) {
			throw new UnsupportedOperationException("An advice method can never be a constructor");
		}
		else {
			// we return null rather than throw an exception so that we behave well
			// in a chain-of-responsibility.
			return null;
		}
	}


	private void bindParameterName(int index, @Nullable String name) {
		this.parameterNameBindings[index] = name;
		this.numberOfRemainingUnboundArguments--;
	}

	/**
	 * If the first parameter is of type JoinPoint or ProceedingJoinPoint, bind "thisJoinPoint" as
	 * parameter name and return true, else return false.
	 */

View on GitHub (pinned to e8729d0438)

Solutions

  1. Do not reuse AspectJAdviceParameterNameDiscoverer for constructor introspection; use a standard discoverer (e.g. DefaultParameterNameDiscoverer) for constructors.
  2. Leave raiseExceptions=false (the default for general use) so it returns null for constructors instead of throwing.
  3. Scope the discoverer to advice method wiring only.

Example fix

// before: reusing the advice discoverer to inspect a constructor
AspectJAdviceParameterNameDiscoverer d = new AspectJAdviceParameterNameDiscoverer(pc);
d.setRaiseExceptions(true);
String[] names = d.getParameterNames(someConstructor);
// after: use a standard discoverer for constructors
String[] names = new DefaultParameterNameDiscoverer().getParameterNames(someConstructor);
Defensive patterns

Strategy: validation

Validate before calling

// Do not use AspectJAdviceParameterNameDiscoverer for constructors.
if (member instanceof Constructor<?>) {
    throw new IllegalArgumentException(
        "Use DefaultParameterNameDiscoverer for constructors; AspectJAdviceParameterNameDiscoverer is method-only");
}

Type guard

private static boolean isAdviceMethodCandidate(Member m) {
    return m instanceof Method;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of spring-projects/spring-framework@e8729d0438 (2026-08-04). Data as JSON: /data/errors/c70309fe063963dd.json. Report an issue: GitHub.