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.util.Assert; 025 026/** 027 * Convenient class for building up pointcuts. 028 * 029 * <p>All methods return {@code ComposablePointcut}, so we can use concise idioms 030 * like in the following example. 031 * 032 * <pre class="code">Pointcut pc = new ComposablePointcut() 033 * .union(classFilter) 034 * .intersection(methodMatcher) 035 * .intersection(pointcut);</pre> 036 * 037 * @author Rod Johnson 038 * @author Juergen Hoeller 039 * @author Rob Harrop 040 * @since 11.11.2003 041 * @see Pointcuts 042 */ 043public class ComposablePointcut implements Pointcut, Serializable { 044 045 /** use serialVersionUID from Spring 1.2 for interoperability */ 046 private static final long serialVersionUID = -2743223737633663832L; 047 048 private ClassFilter classFilter; 049 050 private MethodMatcher methodMatcher; 051 052 053 /** 054 * Create a default ComposablePointcut, with {@code ClassFilter.TRUE} 055 * and {@code MethodMatcher.TRUE}. 056 */ 057 public ComposablePointcut() { 058 this.classFilter = ClassFilter.TRUE; 059 this.methodMatcher = MethodMatcher.TRUE; 060 } 061 062 /** 063 * Create a ComposablePointcut based on the given Pointcut. 064 * @param pointcut the original Pointcut 065 */ 066 public ComposablePointcut(Pointcut pointcut) { 067 Assert.notNull(pointcut, "Pointcut must not be null"); 068 this.classFilter = pointcut.getClassFilter(); 069 this.methodMatcher = pointcut.getMethodMatcher(); 070 } 071 072 /** 073 * Create a ComposablePointcut for the given ClassFilter, 074 * with {@code MethodMatcher.TRUE}. 075 * @param classFilter the ClassFilter to use 076 */ 077 public ComposablePointcut(ClassFilter classFilter) { 078 Assert.notNull(classFilter, "ClassFilter must not be null"); 079 this.classFilter = classFilter; 080 this.methodMatcher = MethodMatcher.TRUE; 081 } 082 083 /** 084 * Create a ComposablePointcut for the given MethodMatcher, 085 * with {@code ClassFilter.TRUE}. 086 * @param methodMatcher the MethodMatcher to use 087 */ 088 public ComposablePointcut(MethodMatcher methodMatcher) { 089 Assert.notNull(methodMatcher, "MethodMatcher must not be null"); 090 this.classFilter = ClassFilter.TRUE; 091 this.methodMatcher = methodMatcher; 092 } 093 094 /** 095 * Create a ComposablePointcut for the given ClassFilter and MethodMatcher. 096 * @param classFilter the ClassFilter to use 097 * @param methodMatcher the MethodMatcher to use 098 */ 099 public ComposablePointcut(ClassFilter classFilter, MethodMatcher methodMatcher) { 100 Assert.notNull(classFilter, "ClassFilter must not be null"); 101 Assert.notNull(methodMatcher, "MethodMatcher must not be null"); 102 this.classFilter = classFilter; 103 this.methodMatcher = methodMatcher; 104 } 105 106 107 /** 108 * Apply a union with the given ClassFilter. 109 * @param other the ClassFilter to apply a union with 110 * @return this composable pointcut (for call chaining) 111 */ 112 public ComposablePointcut union(ClassFilter other) { 113 this.classFilter = ClassFilters.union(this.classFilter, other); 114 return this; 115 } 116 117 /** 118 * Apply an intersection with the given ClassFilter. 119 * @param other the ClassFilter to apply an intersection with 120 * @return this composable pointcut (for call chaining) 121 */ 122 public ComposablePointcut intersection(ClassFilter other) { 123 this.classFilter = ClassFilters.intersection(this.classFilter, other); 124 return this; 125 } 126 127 /** 128 * Apply a union with the given MethodMatcher. 129 * @param other the MethodMatcher to apply a union with 130 * @return this composable pointcut (for call chaining) 131 */ 132 public ComposablePointcut union(MethodMatcher other) { 133 this.methodMatcher = MethodMatchers.union(this.methodMatcher, other); 134 return this; 135 } 136 137 /** 138 * Apply an intersection with the given MethodMatcher. 139 * @param other the MethodMatcher to apply an intersection with 140 * @return this composable pointcut (for call chaining) 141 */ 142 public ComposablePointcut intersection(MethodMatcher other) { 143 this.methodMatcher = MethodMatchers.intersection(this.methodMatcher, other); 144 return this; 145 } 146 147 /** 148 * Apply a union with the given Pointcut. 149 * <p>Note that for a Pointcut union, methods will only match if their 150 * original ClassFilter (from the originating Pointcut) matches as well. 151 * MethodMatchers and ClassFilters from different Pointcuts will never 152 * get interleaved with each other. 153 * @param other the Pointcut to apply a union with 154 * @return this composable pointcut (for call chaining) 155 */ 156 public ComposablePointcut union(Pointcut other) { 157 this.methodMatcher = MethodMatchers.union( 158 this.methodMatcher, this.classFilter, other.getMethodMatcher(), other.getClassFilter()); 159 this.classFilter = ClassFilters.union(this.classFilter, other.getClassFilter()); 160 return this; 161 } 162 163 /** 164 * Apply an intersection with the given Pointcut. 165 * @param other the Pointcut to apply an intersection with 166 * @return this composable pointcut (for call chaining) 167 */ 168 public ComposablePointcut intersection(Pointcut other) { 169 this.classFilter = ClassFilters.intersection(this.classFilter, other.getClassFilter()); 170 this.methodMatcher = MethodMatchers.intersection(this.methodMatcher, other.getMethodMatcher()); 171 return this; 172 } 173 174 175 @Override 176 public ClassFilter getClassFilter() { 177 return this.classFilter; 178 } 179 180 @Override 181 public MethodMatcher getMethodMatcher() { 182 return this.methodMatcher; 183 } 184 185 @Override 186 public boolean equals(Object other) { 187 if (this == other) { 188 return true; 189 } 190 if (!(other instanceof ComposablePointcut)) { 191 return false; 192 } 193 ComposablePointcut otherPointcut = (ComposablePointcut) other; 194 return (this.classFilter.equals(otherPointcut.classFilter) && 195 this.methodMatcher.equals(otherPointcut.methodMatcher)); 196 } 197 198 @Override 199 public int hashCode() { 200 return this.classFilter.hashCode() * 37 + this.methodMatcher.hashCode(); 201 } 202 203 @Override 204 public String toString() { 205 return "ComposablePointcut: " + this.classFilter + ", " + this.methodMatcher; 206 } 207 208}