How do you bind and use a method's return value inside @AfterReturning, and what are the naming rules?
answer
- returning="x" ↔ parameter named x
- Parameter TYPE filters which joins match
- Object = match all return types
- JoinPoint must be first parameter
- pointcut vs value attribute gotcha
basics
~10 sAdd 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 sYou 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@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
Knows returning binds the value to a parameter.
Knows the type-as-filter effect and the JoinPoint-first rule.
Explains erasure, null/void behavior, and the value-vs-pointcut attribute.
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