skip to content

How do you compose named pointcuts using &&, || and !?

level: middleimportance: should knowfreq 45%

answer

  1. && and, || or, ! not
  2. name the composite in its own @Pointcut
  3. precedence: ! then && then ||
  4. mix named + inline designators
  5. parenthesize when unsure

basics

~10 s

Combine named pointcuts inside another @Pointcut (or advice) expression with && (both match), || (either matches) and ! (negation). Example: @Pointcut("serviceMethods() && !readOnlyMethods()").

solid answer

~30 s

Named pointcuts are boolean predicates, so you compose them with the logical operators && (and), || (or), and ! (not). You reference each named pointcut by its name (with parentheses) and combine them either directly in an advice annotation or, better, inside a new @Pointcut to give the combination its own name. For example: @Pointcut("inWebLayer()") void web() {}; @Pointcut("inServiceLayer()") void service() {}; @Pointcut("web() || service()") void inWebOrService() {}. You can also mix named pointcuts with inline designators: @Pointcut("serviceMethods() && @annotation(org.springframework.transaction.annotation.Transactional)"). This layering builds a small vocabulary of intent-revealing pointcuts (e.g. 'controller reads', 'transactional writes') that advice references without repeating raw expressions.

code

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

    @Pointcut("within(com.app.service..*)")
    void inServiceLayer() {}

    @Pointcut("execution(* get*(..)) || execution(* is*(..))")
    void accessors() {}

    // Compose: service methods that are NOT accessors
    @Pointcut("inServiceLayer() && !accessors()")
    void serviceMutations() {}

    @Around("serviceMutations()")
    public Object audit(ProceedingJoinPoint pjp) throws Throwable {
        // audit only real state-changing calls
        return pjp.proceed();
    }
}

go deeper

for a junior

Know the three operators exist and roughly what they do.

for a middle

Compose and name composites, mix named + inline, know precedence.

for a senior

Discuss parameter threading and the XML escaping caveat.

for a principal

Advocate a layered pointcut vocabulary; watch readability and matching-bug risk from precedence.

**Concept.** A pointcut is a boolean predicate over join points. Because they're predicates, you can combine them with the same logical operators AspectJ borrows from C/Java: - `&&` — logical AND: a join point matches only if **both** operands match. - `||` — logical OR: matches if **either** operand matches. - `!` — logical NOT: matches everything the operand does **not** match. **Where composition happens.** You can write a composed expression: 1. Directly in an advice annotation: `@Around("serviceMethods() && !skipped()")`. 2. Inside another `@Pointcut` to *name the combination* — the recommended approach because the composite gets an intent-revealing name and can itself be reused/composed further. ```java @Pointcut("within(com.app.web..*)") void inWebLayer() {} @Pointcut("within(com.app.service..*)") void inServiceLayer() {} // OR: either layer @Pointcut("inWebLayer() || inServiceLayer()") void inWebOrService() {} // AND + NOT: service methods that are NOT getters @Pointcut("execution(* get*(..))") void getters() {} @Pointcut("inServiceLayer() && !getters()") void serviceMutations() {} ``` **Mixing named and inline designators.** Operands can be either named pointcuts or raw designators. A very common pattern is combining a layer pointcut with an annotation match: ```java @Pointcut("inServiceLayer() && @annotation(org.springframework.transaction.annotation.Transactional)") void transactionalService() {} ``` **Precedence & grouping.** `!` binds tightest, then `&&`, then `||` — same as Java. When in doubt, add parentheses: `(a() || b()) && !c()`. Getting precedence wrong silently changes what matches, which is a classic subtle bug. **Parameter binding across composition.** If a named pointcut declares parameters (for `args()`, `this()`, `target()`, `@annotation` binding), a composed pointcut that binds those must thread the parameters through. When you only need matching (not binding), no parameters are required. **Gotchas.** - Operator precedence surprises: `a() || b() && c()` means `a() || (b() && c())`. - `&&` in XML config must be escaped as `&&`; in annotations you write plain `&&`. - A composite pointcut that references pointcuts from other aspects must use fully-qualified names and respect their visibility. - Overly clever compositions hurt readability — name intermediate steps. **When to use.** Compose to express intent precisely ('transactional service writes, excluding getters') and to build a reusable pointcut vocabulary rather than one-off giant expressions.

  • What is the operator precedence of !, &&, || in a pointcut expression?
    Same as Java: ! binds tightest, then &&, then ||. So a() || b() && c() parses as a() || (b() && c()). Use parentheses to force a different grouping and avoid subtle matching bugs.
  • How do you write && when defining a pointcut in XML instead of annotations?
    In Spring XML (aop:pointcut), the & character is XML-special, so you must escape && as &&. In @Pointcut annotations you write plain && with no escaping.

saying these in an interview costs you the question

  • Thinking you can't combine a named pointcut with an inline designator
  • Assuming && / || evaluate left-to-right with equal precedence
  • Forgetting to escape && in XML

context