001/* 002 * Copyright 2002-2019 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.aop.support; 018 019import java.io.Serializable; 020 021import org.springframework.aop.ClassFilter; 022import org.springframework.aop.MethodMatcher; 023import org.springframework.aop.Pointcut; 024import org.springframework.lang.Nullable; 025import org.springframework.util.Assert; 026 027/** 028 * Convenient class for building up pointcuts. 029 * 030 * <p>All methods return {@code ComposablePointcut}, so we can use concise idioms 031 * like in the following example. 032 * 033 * <pre class="code">Pointcut pc = new ComposablePointcut() 034 * .union(classFilter) 035 * .intersection(methodMatcher) 036 * .intersection(pointcut);</pre> 037 * 038 * @author Rod Johnson 039 * @author Juergen Hoeller 040 * @author Rob Harrop 041 * @since 11.11.2003 042 * @see Pointcuts 043 */ 044public class ComposablePointcut implements Pointcut, Serializable { 045 046 /** use serialVersionUID from Spring 1.2 for interoperability. */ 047 private static final long serialVersionUID = -2743223737633663832L; 048 049 private ClassFilter classFilter; 050 051 private MethodMatcher methodMatcher; 052 053 054 /** 055 * Create a default ComposablePointcut, with {@code ClassFilter.TRUE} 056 * and {@code MethodMatcher.TRUE}. 057 */ 058 public ComposablePointcut() { 059 this.classFilter = ClassFilter.TRUE; 060 this.methodMatcher = MethodMatcher.TRUE; 061 } 062 063 /** 064 * Create a ComposablePointcut based on the given Pointcut. 065 * @param pointcut the original Pointcut 066 */ 067 public ComposablePointcut(Pointcut pointcut) { 068 Assert.notNull(pointcut, "Pointcut must not be null"); 069 this.classFilter = pointcut.getClassFilter(); 070 this.methodMatcher = pointcut.getMethodMatcher(); 071 } 072 073 /** 074 * Create a ComposablePointcut for the given ClassFilter, 075 * with {@code MethodMatcher.TRUE}. 076 * @param classFilter the ClassFilter to use 077 */ 078 public ComposablePointcut(ClassFilter classFilter) { 079 Assert.notNull(classFilter, "ClassFilter must not be null"); 080 this.classFilter = classFilter; 081 this.methodMatcher = MethodMatcher.TRUE; 082 } 083 084 /** 085 * Create a ComposablePointcut for the given MethodMatcher, 086 * with {@code ClassFilter.TRUE}. 087 * @param methodMatcher the MethodMatcher to use 088 */ 089 public ComposablePointcut(MethodMatcher methodMatcher) { 090 Assert.notNull(methodMatcher, "MethodMatcher must not be null"); 091 this.classFilter = ClassFilter.TRUE; 092 this.methodMatcher = methodMatcher; 093 } 094 095 /** 096 * Create a ComposablePointcut for the given ClassFilter and MethodMatcher. 097 * @param classFilter the ClassFilter to use 098 * @param methodMatcher the MethodMatcher to use 099 */ 100 public ComposablePointcut(ClassFilter classFilter, MethodMatcher methodMatcher) { 101 Assert.notNull(classFilter, "ClassFilter must not be null"); 102 Assert.notNull(methodMatcher, "MethodMatcher must not be null"); 103 this.classFilter = classFilter; 104 this.methodMatcher = methodMatcher; 105 } 106 107 108 /** 109 * Apply a union with the given ClassFilter. 110 * @param other the ClassFilter to apply a union with 111 * @return this composable pointcut (for call chaining) 112 */ 113 public ComposablePointcut union(ClassFilter other) { 114 this.classFilter = ClassFilters.union(this.classFilter, other); 115 return this; 116 } 117 118 /** 119 * Apply an intersection with the given ClassFilter. 120 * @param other the ClassFilter to apply an intersection with 121 * @return this composable pointcut (for call chaining) 122 */ 123 public ComposablePointcut intersection(ClassFilter other) { 124 this.classFilter = ClassFilters.intersection(this.classFilter, other); 125 return this; 126 } 127 128 /** 129 * Apply a union with the given MethodMatcher. 130 * @param other the MethodMatcher to apply a union with 131 * @return this composable pointcut (for call chaining) 132 */ 133 public ComposablePointcut union(MethodMatcher other) { 134 this.methodMatcher = MethodMatchers.union(this.methodMatcher, other); 135 return this; 136 } 137 138 /** 139 * Apply an intersection with the given MethodMatcher. 140 * @param other the MethodMatcher to apply an intersection with 141 * @return this composable pointcut (for call chaining) 142 */ 143 public ComposablePointcut intersection(MethodMatcher other) { 144 this.methodMatcher = MethodMatchers.intersection(this.methodMatcher, other); 145 return this; 146 } 147 148 /** 149 * Apply a union with the given Pointcut. 150 * <p>Note that for a Pointcut union, methods will only match if their 151 * original ClassFilter (from the originating Pointcut) matches as well. 152 * MethodMatchers and ClassFilters from different Pointcuts will never 153 * get interleaved with each other. 154 * @param other the Pointcut to apply a union with 155 * @return this composable pointcut (for call chaining) 156 */ 157 public ComposablePointcut union(Pointcut other) { 158 this.methodMatcher = MethodMatchers.union( 159 this.methodMatcher, this.classFilter, other.getMethodMatcher(), other.getClassFilter()); 160 this.classFilter = ClassFilters.union(this.classFilter, other.getClassFilter()); 161 return this; 162 } 163 164 /** 165 * Apply an intersection with the given Pointcut. 166 * @param other the Pointcut to apply an intersection with 167 * @return this composable pointcut (for call chaining) 168 */ 169 public ComposablePointcut intersection(Pointcut other) { 170 this.classFilter = ClassFilters.intersection(this.classFilter, other.getClassFilter()); 171 this.methodMatcher = MethodMatchers.intersection(this.methodMatcher, other.getMethodMatcher()); 172 return this; 173 } 174 175 176 @Override 177 public ClassFilter getClassFilter() { 178 return this.classFilter; 179 } 180 181 @Override 182 public MethodMatcher getMethodMatcher() { 183 return this.methodMatcher; 184 } 185 186 @Override 187 public boolean equals(@Nullable Object other) { 188 if (this == other) { 189 return true; 190 } 191 if (!(other instanceof ComposablePointcut)) { 192 return false; 193 } 194 ComposablePointcut otherPointcut = (ComposablePointcut) other; 195 return (this.classFilter.equals(otherPointcut.classFilter) && 196 this.methodMatcher.equals(otherPointcut.methodMatcher)); 197 } 198 199 @Override 200 public int hashCode() { 201 return this.classFilter.hashCode() * 37 + this.methodMatcher.hashCode(); 202 } 203 204 @Override 205 public String toString() { 206 return getClass().getName() + ": " + this.classFilter + ", " + this.methodMatcher; 207 } 208 209}