How do you compose named pointcuts using &&, || and !?
answer
- && and, || or, ! not
- name the composite in its own @Pointcut
- precedence: ! then && then ||
- mix named + inline designators
- parenthesize when unsure
basics
~10 sCombine named pointcuts inside another @Pointcut (or advice) expression with && (both match), || (either matches) and ! (negation). Example: @Pointcut("serviceMethods() && !readOnlyMethods()").
solid answer
~30 sNamed 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@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
Know the three operators exist and roughly what they do.
Compose and name composites, mix named + inline, know precedence.
Discuss parameter threading and the XML escaping caveat.
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