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.ArrayList;
022import java.util.Arrays;
023import java.util.List;
024
025import org.springframework.lang.Nullable;
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 ArrayList<>();
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 ArrayList<>(Arrays.asList(mappedNames));
061        }
062
063        /**
064         * Add another eligible method name, in addition to those already named.
065         * Like the set methods, this method is for use when configuring proxies,
066         * before a proxy is used.
067         * <p><b>NB:</b> This method does not work after the proxy is in
068         * use, as advice chains will be cached.
069         * @param name the name of the additional method that will match
070         * @return this pointcut to allow for multiple additions in one line
071         */
072        public NameMatchMethodPointcut addMethodName(String name) {
073                this.mappedNames.add(name);
074                return this;
075        }
076
077
078        @Override
079        public boolean matches(Method method, Class<?> targetClass) {
080                for (String mappedName : this.mappedNames) {
081                        if (mappedName.equals(method.getName()) || isMatch(method.getName(), mappedName)) {
082                                return true;
083                        }
084                }
085                return false;
086        }
087
088        /**
089         * Return if the given method name matches the mapped name.
090         * <p>The default implementation checks for "xxx*", "*xxx" and "*xxx*" matches,
091         * as well as direct equality. Can be overridden in subclasses.
092         * @param methodName the method name of the class
093         * @param mappedName the name in the descriptor
094         * @return if the names match
095         * @see org.springframework.util.PatternMatchUtils#simpleMatch(String, String)
096         */
097        protected boolean isMatch(String methodName, String mappedName) {
098                return PatternMatchUtils.simpleMatch(mappedName, methodName);
099        }
100
101
102        @Override
103        public boolean equals(@Nullable Object other) {
104                return (this == other || (other instanceof NameMatchMethodPointcut &&
105                                this.mappedNames.equals(((NameMatchMethodPointcut) other).mappedNames)));
106        }
107
108        @Override
109        public int hashCode() {
110                return this.mappedNames.hashCode();
111        }
112
113        @Override
114        public String toString() {
115                return getClass().getName() + ": " + this.mappedNames;
116        }
117
118}