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;
020import java.lang.reflect.Method;
021import java.util.Arrays;
022import java.util.LinkedList;
023import java.util.List;
024
025import org.springframework.util.ObjectUtils;
026import org.springframework.util.PatternMatchUtils;
027
028/**
029 * Pointcut bean for simple method name matches, as an alternative to regexp patterns.
030 *
031 * <p>Does not handle overloaded methods: all methods with a given name will be eligible.
032 *
033 * @author Juergen Hoeller
034 * @author Rod Johnson
035 * @author Rob Harrop
036 * @since 11.02.2004
037 * @see #isMatch
038 */
039@SuppressWarnings("serial")
040public class NameMatchMethodPointcut extends StaticMethodMatcherPointcut implements Serializable {
041
042        private List<String> mappedNames = new LinkedList<String>();
043
044
045        /**
046         * Convenience method when we have only a single method name to match.
047         * Use either this method or {@code setMappedNames}, not both.
048         * @see #setMappedNames
049         */
050        public void setMappedName(String mappedName) {
051                setMappedNames(mappedName);
052        }
053
054        /**
055         * Set the method names defining methods to match.
056         * Matching will be the union of all these; if any match,
057         * the pointcut matches.
058         */
059        public void setMappedNames(String... mappedNames) {
060                this.mappedNames = new LinkedList<String>();
061                if (mappedNames != null) {
062                        this.mappedNames.addAll(Arrays.asList(mappedNames));
063                }
064        }
065
066        /**
067         * Add another eligible method name, in addition to those already named.
068         * Like the set methods, this method is for use when configuring proxies,
069         * before a proxy is used.
070         * <p><b>NB:</b> This method does not work after the proxy is in
071         * use, as advice chains will be cached.
072         * @param name name of the additional method that will match
073         * @return this pointcut to allow for multiple additions in one line
074         */
075        public NameMatchMethodPointcut addMethodName(String name) {
076                this.mappedNames.add(name);
077                return this;
078        }
079
080
081        @Override
082        public boolean matches(Method method, Class<?> targetClass) {
083                for (String mappedName : this.mappedNames) {
084                        if (mappedName.equals(method.getName()) || isMatch(method.getName(), mappedName)) {
085                                return true;
086                        }
087                }
088                return false;
089        }
090
091        /**
092         * Return if the given method name matches the mapped name.
093         * <p>The default implementation checks for "xxx*", "*xxx" and "*xxx*" matches,
094         * as well as direct equality. Can be overridden in subclasses.
095         * @param methodName the method name of the class
096         * @param mappedName the name in the descriptor
097         * @return if the names match
098         * @see org.springframework.util.PatternMatchUtils#simpleMatch(String, String)
099         */
100        protected boolean isMatch(String methodName, String mappedName) {
101                return PatternMatchUtils.simpleMatch(mappedName, methodName);
102        }
103
104
105        @Override
106        public boolean equals(Object other) {
107                return (this == other || (other instanceof NameMatchMethodPointcut &&
108                                ObjectUtils.nullSafeEquals(this.mappedNames, ((NameMatchMethodPointcut) other).mappedNames)));
109        }
110
111        @Override
112        public int hashCode() {
113                return (this.mappedNames != null ? this.mappedNames.hashCode() : 0);
114        }
115
116}