skip to content

What does the @args designator match, and how does it differ from args()? What are its runtime and performance implications?

level: seniorimportance: should knowfreq 30%

answer

  1. annotation on the RUNTIME argument's class
  2. not the parameter, not the declared type
  3. @args = marked type; args = the type itself
  4. runtime residue + early-bean-instantiation cost
  5. element count must match params (use ..)

basics

~20 s

@args matches when the runtime types of the passed arguments are themselves annotated. @args(Validated) matches a call whose single argument's actual class carries @Validated. args() matches by argument type, not by annotation. @args is a runtime check.

solid answer

~50 s

@args(Ann) matches a method-execution join point when the **runtime class of each actual argument** carries the annotation Ann. It is about the annotation on the *type of the argument object*, not an annotation on the parameter and not the parameter's declared type. Because argument objects and their concrete classes are only known when the call happens, @args is a **runtime** designator — like @target/this/target it inserts a per-invocation check and cannot be resolved statically, which can force early bean instantiation during auto-proxying. args(SomeType) differs: it matches by the argument's type (and enables binding the argument), whereas @args matches by an annotation present on that type. The number of elements in @args must equal the method's parameter count (use `..` for flexibility). Retention must be RUNTIME and the annotation's @Target must allow TYPE. A common use: apply advice to any handler receiving a @Validated or domain-specific marked payload.

code

java · 16 lines
java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Sensitive {}

@Sensitive
public class CreditCard { /* ... */ }

@Aspect @Component
class RedactionAspect {
    // Narrow with a STATIC designator first, then the runtime @args check.
    // Matches single-arg methods whose actual argument's class is @Sensitive.
    @Before("execution(* com.example.api..*(..)) && @args(com.example.Sensitive)")
    public void redactLogs(JoinPoint jp) {
        // e.g. mark thread-local so the argument is masked in logs
    }
}

go deeper

for a junior

Roughly: @args cares about the (annotated) type of the argument passed in.

for a middle

Distinguish @args from args and note it's a runtime check on the argument's runtime type.

for a senior

Explain runtime-residue and auto-proxy early-instantiation costs; recommend pairing with a static designator; know the arity rules.

for a principal

Weigh @args against alternatives (e.g. inspecting args inside advice) for performance/complexity; reason about proxy-eligibility side effects across a large bean graph.

## What @args means precisely `@args(Ann)` matches a method-execution join point when the **runtime type (concrete class) of the actual argument(s)** passed to the method is annotated with `Ann`. Critical distinctions: - It is **NOT** an annotation on the *parameter* (that would be a parameter annotation, matched differently and rarely in Spring AOP). - It is **NOT** the argument's declared/static type — it is the **runtime class of the object actually passed**. Example: ```java @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface Sensitive {} @Sensitive class CreditCard {} class PlainNote {} void handle(Object payload) { ... } ``` `@args(Sensitive)` matches `handle(new CreditCard())` (runtime class `CreditCard` is `@Sensitive`) but not `handle(new PlainNote())`, **even though the declared parameter type is `Object` in both cases**. ## @args vs args - `args(com.example.CreditCard)` — matches when the argument's runtime type **is (assignable to)** `CreditCard`, and can **bind** the argument to an advice parameter. It's about the *type*. - `@args(Sensitive)` — matches when the argument's runtime type **is annotated** with `@Sensitive`. It's about *metadata on the type*. Both are runtime designators (they inspect the actual arguments), but they answer different questions: 'is it this type?' vs 'is its type marked with this annotation?'. ## Argument-count rules The designator's element list must correspond to the method's parameters. `@args(Sensitive)` matches only methods with **exactly one** parameter whose runtime arg is `@Sensitive`. For methods with more parameters you enumerate each position or use the `..` wildcard, e.g. `@args(Sensitive, ..)` (first arg annotated, remaining unconstrained) — mirroring how `args(...)` handles counts. ## Runtime and performance implications `@args`, along with `@target`, `this`, `target`, and `args`, **cannot be evaluated statically** because they depend on values only available at call time. Consequences: - Spring inserts a **runtime residue check** on each matched invocation. - During auto-proxy creation, because Spring cannot statically exclude beans, such pointcuts can cause **beans to be instantiated early**, sometimes producing *'is not eligible for getting processed by all BeanPostProcessors'* warnings and subtle ordering problems. - For hot paths, the per-call type/annotation inspection adds overhead versus static designators (`@annotation`, `@within`, `execution`, `within`). **Guidance:** prefer combining `@args` with a **static** designator to narrow the candidate set first, e.g. `execution(* com.example.api..*(..)) && @args(Sensitive)`. This limits both proxy candidates and runtime checks. ## Requirements - Annotation `@Retention(RUNTIME)`. - Annotation `@Target` must permit `TYPE` (it is placed on the argument's class). ## Typical uses - Advising any endpoint/handler that receives a payload marked `@Validated` or a domain marker like `@Pii`/`@Sensitive` for logging redaction, encryption, or audit — regardless of the specific method signatures.

  • Does @args look at the declared parameter type or the runtime object type?
    The runtime object type. Even if the parameter is declared as Object or a supertype, @args inspects the concrete class of the value actually passed at call time for the annotation.
  • How would you reduce the cost of an @args pointcut?
    Combine it with a static designator (execution/within/@within) so Spring narrows proxy candidates statically and only performs the runtime @args check on an already-small set of methods, cutting both early-instantiation and per-call overhead.

saying these in an interview costs you the question

  • Saying @args matches a parameter annotation rather than an annotation on the argument's type
  • Claiming it uses the declared parameter type instead of the runtime type
  • Thinking @args is a static match with no per-call cost
  • Ignoring that the element count must match the method's arity

context