skip to content

How do you bind and use a method's return value inside @AfterReturning, and what are the naming rules?

level: middleimportance: must knowfreq 55%

answer

  1. returning="x" ↔ parameter named x
  2. Parameter TYPE filters which joins match
  3. Object = match all return types
  4. JoinPoint must be first parameter
  5. pointcut vs value attribute gotcha

basics

~10 s

Add returning="paramName" to @AfterReturning and declare a matching parameter of that name in the advice method. The parameter receives the returned value. The name must match the parameter, not the pointcut expression.

solid answer

~40 s

You set the annotation's returning attribute to a name that must match a parameter in the advice method: @AfterReturning(pointcut="...", returning="result") void log(Object result). Spring passes the actual returned value into result at runtime. Two important effects: (1) the declared parameter TYPE acts as an extra filter — the advice only runs for join points whose return value is assignable to that type (a null return does not match a primitive/typed parameter in the usual way). Declare Object to match everything. (2) If you only pass a pointcut plus returning, use the pointcut attribute name explicitly; the bare value attribute is the pointcut when there's no returning. You can also add a JoinPoint (or the returning object) as parameters; JoinPoint must be first if present.

code

java · 21 lines
java
@Aspect
@Component
public class ResultLoggingAspect {

    // Only advises methods whose return is assignable to List
    @AfterReturning(
        pointcut = "execution(* com.app.CatalogService.find*(..))",
        returning = "items")
    public void afterFind(JoinPoint jp, List<?> items) {
        System.out.printf("%s returned %d items%n",
            jp.getSignature().getName(), items.size());
    }

    // Matches ANY successful return because the type is Object
    @AfterReturning(
        pointcut = "execution(* com.app.OrderService.*(..))",
        returning = "result")
    public void afterAny(Object result) {
        System.out.println("returned: " + result);
    }
}

go deeper

for a junior

Knows returning binds the value to a parameter.

for a middle

Knows the type-as-filter effect and the JoinPoint-first rule.

for a senior

Explains erasure, null/void behavior, and the value-vs-pointcut attribute.

for a principal

Discusses how typed binding shapes aspect design and matching predictability.

## Syntax ```java @AfterReturning( pointcut = "execution(* com.app.*Service.*(..))", returning = "result") public void afterReturning(JoinPoint jp, Object result) { ... } ``` - `returning = "result"` names a **parameter of the advice method**, not an expression in the pointcut. Spring binds the method's return value to that parameter at runtime. - If you also want method metadata, declare a `JoinPoint` (or `org.aspectj.lang.JoinPoint`) parameter. **When present, `JoinPoint` must be the first parameter.** ## The `pointcut` vs `value` attribute gotcha `@AfterReturning` has both a `value` and a `pointcut` attribute for the pointcut expression. When you also supply `returning`, you must name the pointcut attribute explicitly: `@AfterReturning(pointcut = "...", returning = "result")`. Using `value` together with `returning` is allowed too, but the common, readable form uses `pointcut`. A frequent mistake is writing `@AfterReturning("...", returning="result")` and being confused about which attribute the string binds to — the positional string is `value`, which is the pointcut. ## Type acts as a matching filter The **declared type** of the returning parameter narrows matching: the advice runs **only** when the returned value is assignable to that type. For example: ```java @AfterReturning(pointcut = "...", returning = "orders") public void afterList(List<Order> orders) { ... } ``` This fires only for methods returning a `List` (or subtype). Methods returning something else are not advised by this advice. To match every successful return regardless of type, declare the parameter as `Object`. Generics are erased at runtime, so `List<Order>` filters on `List`, not on the element type — the `<Order>` gives you a compile-time cast convenience only (and an unchecked warning), Spring cannot verify the element type. ## Void and null returns - For methods declared `void`, the returned value is effectively `null`; binding an `Object result` gives `null`. - If the parameter type is a specific class and the runtime value is `null`, matching behavior follows AspectJ's assignability rules — commonly the advice with a specific non-primitive type still runs with `null`, but relying on typed binding for null-returning join points is fragile; use `Object` when you need to observe those too. ## Putting it together Use the bound value for logging, metrics, cache writes, or conditional follow-up. Remember you're observing a copy of the reference — you can inspect it and mutate the pointed-to object, but you cannot swap what the caller receives.

  • Why might your @AfterReturning advice never fire even though the pointcut looks right?
    The declared type of the returning parameter filters matching: if the method returns a type not assignable to that parameter type, the advice is skipped. Switching the parameter to Object usually fixes it. Self-invocation bypassing the proxy is the other common cause.
  • Does returning="result" refer to the method's return statement or a parameter?
    A parameter of the advice method. Spring binds the runtime return value into the advice parameter whose name equals the returning string.

saying these in an interview costs you the question

  • Thinking returning names something in the target method rather than the advice parameter
  • Not knowing the parameter type restricts which join points match
  • Believing generic element types (List<Order>) are checked at runtime

context