skip to content

Explain the difference between the * and .. wildcards in an execution() pointcut, giving package, type, method-name, and parameter examples.

level: middleimportance: should knowfreq 44%

answer

  1. = one slot, .. = many slots
  2. .. only in package paths + params
  3. service.*.* = direct only
  4. service..*.* = + sub-packages
  5. (String, ..) prefix / (.., String) suffix

basics

~10 s
  • matches exactly one item (one name segment, one type, one parameter). .. matches zero or more — in package position it spans sub-packages, in the parameter position it spans any number of arguments.

solid answer

~40 s

`*` is the single-element wildcard and `..` is the multi-element wildcard. In a method name, `get*` matches names starting with get; `*` alone matches any single method name. In a return/param type, `*` means any one type. In a package path, `com.app.*` matches types directly in that package only, while `com.app..` matches com.app plus all sub-packages. In parameters, `(*)` means exactly one argument, `(*, *)` exactly two, whereas `(..)` means zero-or-more arguments; you can mix them: `(String, ..)` is a String followed by anything. The key mental model: `*` = 'exactly one slot', `..` = 'any number of slots including none' — and `..` only appears in package paths and parameter lists.

code

java · 20 lines
java
@Aspect
@Component
public class WildcardAspect {

    // Only classes DIRECTLY in com.app.service (NOT sub-packages)
    @Pointcut("execution(* com.app.service.*.*(..))")
    public void directOnly() {}

    // com.app.service AND every sub-package
    @Pointcut("execution(* com.app.service..*.*(..))")
    public void includingSubPackages() {}

    // Exactly two args, first is a String, second any type
    @Pointcut("execution(* com.app..*(String, *))")
    public void stringThenAny() {}

    // A String somewhere as the LAST argument, any others before
    @Pointcut("execution(* com.app..*(.., String))")
    public void trailingString() {}
}

go deeper

for a junior

Should know * = one and .. = many at a high level.

for a middle

Should give correct package and parameter examples and know the single-dot trap.

for a senior

Should explain positional legality of .. and the prefix/suffix parameter forms.

for a principal

Should connect wildcard breadth to performance and 'advice not firing' debugging.

## Two wildcards, two jobs AspectJ pointcuts use exactly two wildcards inside `execution()`: - **`*`** — matches **one** item. One method-name (or part of one), one type, one type-name segment, or exactly **one** parameter. - **`..`** — matches **zero or more** items. It is only legal in **two positions**: inside a **package/type path** (spanning nested packages) and inside the **parameter list** (spanning any number of arguments). ## By position ### Method name - `*` → any method name (`execution(* *(..))`) - `find*` → names starting with `find` - `*ById` → names ending with `ById` - `*` can also be a fragment: `get*Name` matches `getFirstName`, `getName`. ### Return / parameter type - `*` → any single type: `execution(* find*(*))` = one arg of any type. - You cannot write `..` as a return type — return type is a single required slot. ### Package / declaring type - `com.app.service.*` → types **directly** in `com.app.service` (not `com.app.service.impl`). - `com.app.service..*` → types in `com.app.service` **and all sub-packages** (`..` then `*` for the class name). - `*Service` → any type name ending in Service. - `com.app..*Service` → any `*Service` type anywhere under `com.app`. ### Parameters - `()` → no parameters. - `(*)` → exactly one, any type. - `(*, *)` → exactly two, any types. - `(..)` → zero or more, any types. - `(String, ..)` → String first, then anything. - `(.., String)` → anything, ending in a String. - `(*, .., String)` → a first arg of any type, then anything, then a trailing String. ## The classic trap `execution(* com.app.service.*.*(..))` does **NOT** cover sub-packages — the `.*.` in the middle is 'any class **directly** in com.app.service'. To include sub-packages you must use the double dot: `execution(* com.app.service..*.*(..))`. Interviewers love this one. ## Why it matters A too-broad `..` in a package path silently advises far more beans than intended (performance + surprising behavior); a too-narrow single `*` silently misses beans in sub-packages (the aspect appears not to run). Getting `*` vs `..` right is the single most common source of 'my advice isn't firing' bugs.

  • Why might an aspect 'silently not fire' on classes in an impl sub-package?
    The pointcut probably used a single dot (com.app.service.*.*) which matches only types directly in the package. Sub-packages like com.app.service.impl need the double-dot form com.app.service..*.*.
  • Can .. be used as a return-type pattern?
    No. The return type is a single mandatory slot, so only * or a concrete type is valid there. .. is legal only in package paths and parameter lists.

saying these in an interview costs you the question

  • Claiming * matches multiple parameters or multiple packages
  • Thinking com.app.service.* includes sub-packages
  • Using .. as a return type
  • Believing (..) and (*) are interchangeable

context