0
# Pointcut Implementations
1
2
Various pointcut implementations for different matching strategies including name-based, regular expression, annotation-based, and composable pointcuts. These implementations provide flexible ways to define where advice should be applied in your application, from simple method name patterns to complex AspectJ expressions.
3
4
## Capabilities
5
6
### Composable Pointcuts
7
8
Pointcut implementation that allows combining multiple pointcuts using union and intersection operations.
9
10
```java { .api }
11
public class ComposablePointcut implements Pointcut, Serializable {
12
/**
13
* Create a default ComposablePointcut, with {@code ClassFilter.TRUE}
14
* and {@code MethodMatcher.TRUE}.
15
*/
16
public ComposablePointcut();
17
18
/**
19
* Create a ComposablePointcut based on the given Pointcut.
20
* @param pointcut the original Pointcut
21
*/
22
public ComposablePointcut(Pointcut pointcut);
23
24
/**
25
* Create a ComposablePointcut for the given ClassFilter,
26
* with {@code MethodMatcher.TRUE}.
27
* @param classFilter the ClassFilter to use
28
*/
29
public ComposablePointcut(ClassFilter classFilter);
30
31
/**
32
* Create a ComposablePointcut for the given MethodMatcher,
33
* with {@code ClassFilter.TRUE}.
34
* @param methodMatcher the MethodMatcher to use
35
*/
36
public ComposablePointcut(MethodMatcher methodMatcher);
37
38
/**
39
* Create a ComposablePointcut for the given ClassFilter and MethodMatcher.
40
* @param classFilter the ClassFilter to use
41
* @param methodMatcher the MethodMatcher to use
42
*/
43
public ComposablePointcut(ClassFilter classFilter, MethodMatcher methodMatcher);
44
45
/**
46
* Apply a union with the given Pointcut.
47
* @param other the Pointcut to apply a union with
48
* @return this composable pointcut (for call chaining)
49
*/
50
public ComposablePointcut union(Pointcut other);
51
52
/**
53
* Apply an intersection with the given Pointcut.
54
* @param other the Pointcut to apply an intersection with
55
* @return this composable pointcut (for call chaining)
56
*/
57
public ComposablePointcut intersection(Pointcut other);
58
59
/**
60
* Apply a union with the given ClassFilter.
61
* @param other the ClassFilter to apply a union with
62
* @return this composable pointcut (for call chaining)
63
*/
64
public ComposablePointcut union(ClassFilter other);
65
66
/**
67
* Apply an intersection with the given ClassFilter.
68
* @param other the ClassFilter to apply an intersection with
69
* @return this composable pointcut (for call chaining)
70
*/
71
public ComposablePointcut intersection(ClassFilter other);
72
73
/**
74
* Apply a union with the given MethodMatcher.
75
* @param other the MethodMatcher to apply a union with
76
* @return this composable pointcut (for call chaining)
77
*/
78
public ComposablePointcut union(MethodMatcher other);
79
80
/**
81
* Apply an intersection with the given MethodMatcher.
82
* @param other the MethodMatcher to apply an intersection with
83
* @return this composable pointcut (for call chaining)
84
*/
85
public ComposablePointcut intersection(MethodMatcher other);
86
87
@Override
88
public ClassFilter getClassFilter();
89
90
@Override
91
public MethodMatcher getMethodMatcher();
92
}
93
```
94
95
### Name-Based Pointcuts
96
97
Pointcut implementations that match methods based on method names or patterns.
98
99
```java { .api }
100
public class NameMatchMethodPointcut extends StaticMethodMatcherPointcut implements Serializable {
101
/**
102
* Convenience method when we have only a single method name to match.
103
* Use either this method or {@code setMappedNames}, not both.
104
* @param mappedName the name of the method to match
105
* @see #setMappedNames
106
*/
107
public void setMappedName(String mappedName);
108
109
/**
110
* Set the method names defining methods to match.
111
* Matching will be the union of all these; if any match, the pointcut matches.
112
* @param mappedNames the method names to match
113
*/
114
public void setMappedNames(String... mappedNames);
115
116
/**
117
* Add another eligible method name, in addition to those already named.
118
* Like the set methods, this method is for use when configuring proxies,
119
* before a proxy is used.
120
* <p><b>NB:</b> This method does not work after the proxy is in
121
* use, as advice chains will be cached.
122
* @param name name of the additional method that will match
123
* @return this pointcut to allow for multiple additions in one line
124
*/
125
public NameMatchMethodPointcut addMethodName(String name);
126
127
@Override
128
public boolean matches(Method method, Class<?> targetClass);
129
130
@Override
131
public boolean equals(Object other);
132
133
@Override
134
public int hashCode();
135
}
136
```
137
138
### Regular Expression Pointcuts
139
140
Pointcut implementations using regular expressions for method matching.
141
142
```java { .api }
143
public abstract class AbstractRegexpMethodPointcut extends StaticMethodMatcherPointcut implements Serializable {
144
/**
145
* Convenience method when we have only a single pattern.
146
* Use either this method or {@code setPatterns}, not both.
147
* @param pattern the pattern to match
148
* @see #setPatterns
149
*/
150
public void setPattern(String pattern);
151
152
/**
153
* Set the regular expressions defining methods to match.
154
* Matching will be the union of all these; if any match, the pointcut matches.
155
* @param patterns the patterns to match
156
*/
157
public void setPatterns(String... patterns);
158
159
/**
160
* Return the regular expressions for method matching.
161
*/
162
public String[] getPatterns();
163
164
/**
165
* Try to match the regular expression against the fully qualified name
166
* of the target class as well as against the method's declaring class.
167
*/
168
@Override
169
public boolean matches(Method method, Class<?> targetClass);
170
171
/**
172
* Subclasses must implement this to initialize regex pointcuts.
173
* Can be invoked multiple times.
174
* <p>This method will be invoked from the {@code setPatterns} method,
175
* and also on deserialization.
176
* @param patterns the patterns to initialize
177
* @throws IllegalArgumentException in case of an invalid pattern
178
*/
179
protected abstract void initPatternRepresentation(String[] patterns) throws IllegalArgumentException;
180
181
/**
182
* Does the pattern at the given index match the given String?
183
* @param patternIndex the index of the pattern to match against
184
* @param str the String to match
185
* @return whether there's a match
186
*/
187
protected abstract boolean matches(String pattern, int patternIndex);
188
}
189
190
public class JdkRegexpMethodPointcut extends AbstractRegexpMethodPointcut {
191
/**
192
* Internal method to initialize the {@code Pattern} representation of the pointcut.
193
*/
194
@Override
195
protected void initPatternRepresentation(String[] patterns) throws PatternSyntaxException;
196
197
/**
198
* Does the pattern at the given index match this string?
199
*/
200
@Override
201
protected boolean matches(String pattern, int patternIndex);
202
}
203
```
204
205
### Control Flow Pointcuts
206
207
Pointcut that matches methods executing under a specific control flow.
208
209
```java { .api }
210
public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher, Serializable {
211
/**
212
* Construct a new pointcut that matches all methods executing
213
* under a class with the given name, in any package.
214
* @param clazz the clazz
215
*/
216
public ControlFlowPointcut(Class<?> clazz);
217
218
/**
219
* Construct a new pointcut that matches all methods executing
220
* under a class with the given name, in any package.
221
* @param clazz the clazz
222
* @param methodName the name of the method (may be {@code null})
223
*/
224
public ControlFlowPointcut(Class<?> clazz, String methodName);
225
226
/**
227
* Subclasses can override this for greater filtering (and performance).
228
*/
229
@Override
230
public boolean matches(Class<?> clazz);
231
232
/**
233
* Subclasses can override this if it's possible to filter out
234
* some candidate classes.
235
*/
236
@Override
237
public boolean matches(Method method, Class<?> targetClass);
238
239
@Override
240
public boolean isRuntime();
241
242
@Override
243
public boolean matches(Method method, Class<?> targetClass, Object... args);
244
245
@Override
246
public ClassFilter getClassFilter();
247
248
@Override
249
public MethodMatcher getMethodMatcher();
250
}
251
```
252
253
### Annotation-Based Pointcuts
254
255
Pointcut implementations that match based on annotations present on classes or methods.
256
257
```java { .api }
258
public class AnnotationMatchingPointcut implements Pointcut {
259
/**
260
* Create a new AnnotationMatchingPointcut for which both the class and method
261
* annotations will be checked.
262
* @param classAnnotationType the annotation type to check at the class level
263
* (can be {@code null})
264
* @param methodAnnotationType the annotation type to check at the method level
265
* (can be {@code null})
266
*/
267
public AnnotationMatchingPointcut(Class<? extends Annotation> classAnnotationType,
268
Class<? extends Annotation> methodAnnotationType);
269
270
/**
271
* Create a new AnnotationMatchingPointcut for the given annotation type.
272
* @param classAnnotationType the annotation type to check at the class level
273
* @param checkInherited whether to explicitly check the superclasses and
274
* interfaces for the annotation type as well (even if the annotation type
275
* is not marked as inherited itself)
276
*/
277
public AnnotationMatchingPointcut(Class<? extends Annotation> classAnnotationType, boolean checkInherited);
278
279
/**
280
* Factory method for an AnnotationMatchingPointcut that matches
281
* all methods carrying the specified annotation at the class level.
282
* @param annotationType the annotation type to check at the class level
283
* @return the corresponding AnnotationMatchingPointcut
284
*/
285
public static AnnotationMatchingPointcut forClassAnnotation(Class<? extends Annotation> annotationType);
286
287
/**
288
* Factory method for an AnnotationMatchingPointcut that matches
289
* all methods carrying the specified annotation at the method level.
290
* @param annotationType the annotation type to check at the method level
291
* @return the corresponding AnnotationMatchingPointcut
292
*/
293
public static AnnotationMatchingPointcut forMethodAnnotation(Class<? extends Annotation> annotationType);
294
295
@Override
296
public ClassFilter getClassFilter();
297
298
@Override
299
public MethodMatcher getMethodMatcher();
300
}
301
302
public class AnnotationClassFilter implements ClassFilter {
303
/**
304
* Create a new AnnotationClassFilter for the given annotation type.
305
* @param annotationType the annotation type to look for
306
*/
307
public AnnotationClassFilter(Class<? extends Annotation> annotationType);
308
309
/**
310
* Create a new AnnotationClassFilter for the given annotation type.
311
* @param annotationType the annotation type to look for
312
* @param checkInherited whether to explicitly check the superclasses and
313
* interfaces for the annotation type as well (even if the annotation type
314
* is not marked as inherited itself)
315
*/
316
public AnnotationClassFilter(Class<? extends Annotation> annotationType, boolean checkInherited);
317
318
@Override
319
public boolean matches(Class<?> clazz);
320
}
321
322
public class AnnotationMethodMatcher extends StaticMethodMatcher {
323
/**
324
* Create a new AnnotationMethodMatcher for the given annotation type.
325
* @param annotationType the annotation type to look for
326
*/
327
public AnnotationMethodMatcher(Class<? extends Annotation> annotationType);
328
329
/**
330
* Create a new AnnotationMethodMatcher for the given annotation type.
331
* @param annotationType the annotation type to look for
332
* @param checkInherited whether to explicitly check the superclasses and
333
* interfaces for the annotation type as well (even if the annotation type
334
* is not marked as inherited itself)
335
*/
336
public AnnotationMethodMatcher(Class<? extends Annotation> annotationType, boolean checkInherited);
337
338
@Override
339
public boolean matches(Method method, Class<?> targetClass);
340
}
341
```
342
343
### Static Method Matcher Base Classes
344
345
Base classes for implementing static method matchers (no runtime checks needed).
346
347
```java { .api }
348
public abstract class StaticMethodMatcher implements MethodMatcher {
349
@Override
350
public final boolean isRuntime();
351
352
@Override
353
public final boolean matches(Method method, Class<?> targetClass, Object... args);
354
355
/**
356
* Subclasses must implement this to return {@code true} if the method
357
* matches. Note that there will be no runtime check (i.e. no check on the
358
* method's arguments) if this method returns {@code false}.
359
* @param method the candidate method
360
* @param targetClass target class (may be {@code null}, in which case
361
* the candidate class must be taken to be the method's declaring class)
362
* @return whether or not this method matches statically
363
*/
364
public abstract boolean matches(Method method, Class<?> targetClass);
365
}
366
367
public abstract class StaticMethodMatcherPointcut extends StaticMethodMatcher implements Pointcut {
368
/**
369
* Set the {@link ClassFilter} to use for this pointcut.
370
* Default is {@link ClassFilter#TRUE}.
371
*/
372
public void setClassFilter(ClassFilter classFilter);
373
374
@Override
375
public ClassFilter getClassFilter();
376
377
@Override
378
public final MethodMatcher getMethodMatcher();
379
}
380
381
public abstract class DynamicMethodMatcher implements MethodMatcher {
382
@Override
383
public final boolean isRuntime();
384
385
/**
386
* Can override to add preconditions for dynamic matching. This implementation
387
* always returns true.
388
*/
389
@Override
390
public boolean matches(Method method, Class<?> targetClass);
391
392
/**
393
* Must override to implement runtime matching.
394
* The result of the 2-parameter {@link #matches(Method, Class)} method
395
* is taken into account for static matching checks already.
396
* @param method the candidate method
397
* @param targetClass the target class
398
* @param args arguments to the method
399
* @return whether there's a runtime match
400
*/
401
public abstract boolean matches(Method method, Class<?> targetClass, Object... args);
402
}
403
404
public abstract class DynamicMethodMatcherPointcut extends DynamicMethodMatcher implements Pointcut {
405
/**
406
* Set the {@link ClassFilter} to use for this pointcut.
407
* Default is {@link ClassFilter#TRUE}.
408
*/
409
public void setClassFilter(ClassFilter classFilter);
410
411
@Override
412
public ClassFilter getClassFilter();
413
414
@Override
415
public final MethodMatcher getMethodMatcher();
416
}
417
```
418
419
### Utility Classes
420
421
Utility classes providing static methods for working with pointcuts, class filters, and method matchers.
422
423
```java { .api }
424
public abstract class Pointcuts {
425
/**
426
* Match all methods that <i>either</i> (or both) of the given pointcuts matches.
427
* @param pc1 the first Pointcut
428
* @param pc2 the second Pointcut
429
* @return a distinct Pointcut that matches all methods that either
430
* of the given Pointcuts matches
431
*/
432
public static Pointcut union(Pointcut pc1, Pointcut pc2);
433
434
/**
435
* Match all methods that <i>both</i> the given pointcuts match.
436
* @param pc1 the first Pointcut
437
* @param pc2 the second Pointcut
438
* @return a distinct Pointcut that matches all methods that both
439
* of the given Pointcuts match
440
*/
441
public static Pointcut intersection(Pointcut pc1, Pointcut pc2);
442
443
/**
444
* Perform the least expensive check for a pointcut match.
445
* @param pointcut the pointcut to match
446
* @param method the candidate method
447
* @param targetClass the target class
448
* @param args arguments to the method
449
* @return whether there's a runtime match
450
*/
451
public static boolean matches(Pointcut pointcut, Method method, Class<?> targetClass, Object... args);
452
}
453
454
public abstract class ClassFilters {
455
/**
456
* Match all classes that <i>either</i> (or both) of the given ClassFilters matches.
457
* @param cf1 the first ClassFilter
458
* @param cf2 the second ClassFilter
459
* @return a distinct ClassFilter that matches all classes that either
460
* of the given ClassFilter matches
461
*/
462
public static ClassFilter union(ClassFilter cf1, ClassFilter cf2);
463
464
/**
465
* Match all classes that <i>both</i> the given ClassFilters match.
466
* @param cf1 the first ClassFilter
467
* @param cf2 the second ClassFilter
468
* @return a distinct ClassFilter that matches all classes that both
469
* of the given ClassFilters match
470
*/
471
public static ClassFilter intersection(ClassFilter cf1, ClassFilter cf2);
472
}
473
474
public abstract class MethodMatchers {
475
/**
476
* Match all methods that <i>either</i> (or both) of the given MethodMatchers matches.
477
* @param mm1 the first MethodMatcher
478
* @param mm2 the second MethodMatcher
479
* @return a distinct MethodMatcher that matches all methods that either
480
* of the given MethodMatchers matches
481
*/
482
public static MethodMatcher union(MethodMatcher mm1, MethodMatcher mm2);
483
484
/**
485
* Match all methods that <i>both</i> the given MethodMatchers match.
486
* @param mm1 the first MethodMatcher
487
* @param mm2 the second MethodMatcher
488
* @return a distinct MethodMatcher that matches all methods that both
489
* of the given MethodMatchers match
490
*/
491
public static MethodMatcher intersection(MethodMatcher mm1, MethodMatcher mm2);
492
}
493
```
494
495
### Expression Pointcuts
496
497
Interface for pointcuts that use string expressions for definition.
498
499
```java { .api }
500
public interface ExpressionPointcut {
501
/**
502
* Return the String expression for this pointcut.
503
* @return the String expression
504
*/
505
String getExpression();
506
}
507
```
508
509
## Usage Examples
510
511
### Creating Composable Pointcuts
512
513
```java
514
// Start with a basic name-based pointcut
515
NameMatchMethodPointcut namePointcut = new NameMatchMethodPointcut();
516
namePointcut.setMappedNames("save*", "update*", "delete*");
517
518
// Create annotation-based pointcut
519
AnnotationMatchingPointcut annotationPointcut =
520
AnnotationMatchingPointcut.forMethodAnnotation(Transactional.class);
521
522
// Combine them using union
523
ComposablePointcut composablePointcut = new ComposablePointcut(namePointcut)
524
.union(annotationPointcut);
525
526
// Add class filter to restrict to service classes
527
ClassFilter serviceFilter = new AnnotationClassFilter(Service.class);
528
composablePointcut.intersection(serviceFilter);
529
530
// Create advisor with composed pointcut
531
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(
532
composablePointcut,
533
new LoggingInterceptor()
534
);
535
```
536
537
### Regular Expression Pointcuts
538
539
```java
540
// Create regex pointcut for service layer methods
541
JdkRegexpMethodPointcut regexPointcut = new JdkRegexpMethodPointcut();
542
regexPointcut.setPatterns(
543
".*\\.service\\..*Service\\..*",
544
".*\\.repository\\..*Repository\\.find.*",
545
".*\\.dao\\..*Dao\\.get.*"
546
);
547
548
// Use in advisor
549
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(
550
regexPointcut,
551
new PerformanceMonitorInterceptor()
552
);
553
```
554
555
### Control Flow Pointcuts
556
557
```java
558
// Match methods called from specific control flow
559
ControlFlowPointcut controlFlowPointcut = new ControlFlowPointcut(
560
UserController.class,
561
"handleRequest"
562
);
563
564
// All methods called during UserController.handleRequest() execution
565
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(
566
controlFlowPointcut,
567
new SecurityInterceptor()
568
);
569
```
570
571
### Dynamic Method Matchers
572
573
```java
574
// Custom dynamic matcher based on method parameters
575
DynamicMethodMatcher dynamicMatcher = new DynamicMethodMatcher() {
576
@Override
577
public boolean matches(Method method, Class<?> targetClass) {
578
// Static check: method must have parameters
579
return method.getParameterCount() > 0;
580
}
581
582
@Override
583
public boolean matches(Method method, Class<?> targetClass, Object... args) {
584
// Dynamic check: first parameter must be non-null String
585
return args.length > 0 &&
586
args[0] instanceof String &&
587
args[0] != null;
588
}
589
};
590
591
// Convert to pointcut
592
DynamicMethodMatcherPointcut dynamicPointcut = new DynamicMethodMatcherPointcut() {
593
@Override
594
public boolean matches(Method method, Class<?> targetClass) {
595
return dynamicMatcher.matches(method, targetClass);
596
}
597
598
@Override
599
public boolean matches(Method method, Class<?> targetClass, Object... args) {
600
return dynamicMatcher.matches(method, targetClass, args);
601
}
602
};
603
```
604
605
### Custom Static Method Matcher
606
607
```java
608
// Match methods with specific return type
609
public class ReturnTypeMethodMatcher extends StaticMethodMatcher {
610
private final Class<?> expectedReturnType;
611
612
public ReturnTypeMethodMatcher(Class<?> expectedReturnType) {
613
this.expectedReturnType = expectedReturnType;
614
}
615
616
@Override
617
public boolean matches(Method method, Class<?> targetClass) {
618
return expectedReturnType.isAssignableFrom(method.getReturnType());
619
}
620
}
621
622
// Use the custom matcher
623
ReturnTypeMethodMatcher stringReturnMatcher = new ReturnTypeMethodMatcher(String.class);
624
StaticMethodMatcherPointcut pointcut = new StaticMethodMatcherPointcut() {
625
@Override
626
public boolean matches(Method method, Class<?> targetClass) {
627
return stringReturnMatcher.matches(method, targetClass);
628
}
629
};
630
```
631
632
### Combining Multiple Filters
633
634
```java
635
// Create complex pointcut using utility methods
636
ClassFilter serviceOrController = ClassFilters.union(
637
new AnnotationClassFilter(Service.class),
638
new AnnotationClassFilter(Controller.class)
639
);
640
641
MethodMatcher publicMethods = new MethodMatcher() {
642
@Override
643
public boolean matches(Method method, Class<?> targetClass) {
644
return Modifier.isPublic(method.getModifiers());
645
}
646
647
@Override
648
public boolean isRuntime() {
649
return false;
650
}
651
652
@Override
653
public boolean matches(Method method, Class<?> targetClass, Object... args) {
654
throw new UnsupportedOperationException();
655
}
656
};
657
658
MethodMatcher nonGetterMethods = new StaticMethodMatcher() {
659
@Override
660
public boolean matches(Method method, Class<?> targetClass) {
661
return !method.getName().startsWith("get") &&
662
!method.getName().startsWith("is");
663
}
664
};
665
666
MethodMatcher combinedMethodMatcher = MethodMatchers.intersection(
667
publicMethods,
668
nonGetterMethods
669
);
670
671
// Create final pointcut
672
ComposablePointcut finalPointcut = new ComposablePointcut(
673
serviceOrController,
674
combinedMethodMatcher
675
);
676
```