001/*
002 * Copyright 2002-2015 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.web.bind.annotation.support;
018
019import java.lang.reflect.Method;
020import java.lang.reflect.Proxy;
021import java.util.Arrays;
022import java.util.Collections;
023import java.util.HashSet;
024import java.util.LinkedHashSet;
025import java.util.Set;
026import java.util.concurrent.ConcurrentHashMap;
027
028import org.springframework.core.BridgeMethodResolver;
029import org.springframework.core.annotation.AnnotationUtils;
030import org.springframework.util.ClassUtils;
031import org.springframework.util.ReflectionUtils;
032import org.springframework.web.bind.annotation.InitBinder;
033import org.springframework.web.bind.annotation.ModelAttribute;
034import org.springframework.web.bind.annotation.RequestMapping;
035import org.springframework.web.bind.annotation.SessionAttributes;
036
037/**
038 * Support class for resolving web method annotations in a handler type.
039 * Processes {@code @RequestMapping}, {@code @InitBinder},
040 * {@code @ModelAttribute} and {@code @SessionAttributes}.
041 *
042 * <p>Used by {@link org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter}
043 * and {@link org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter}.
044 *
045 * @author Juergen Hoeller
046 * @since 2.5.2
047 * @see org.springframework.web.bind.annotation.RequestMapping
048 * @see org.springframework.web.bind.annotation.InitBinder
049 * @see org.springframework.web.bind.annotation.ModelAttribute
050 * @see org.springframework.web.bind.annotation.SessionAttributes
051 * @deprecated as of 4.3, in favor of the {@code HandlerMethod}-based MVC infrastructure
052 */
053@Deprecated
054public class HandlerMethodResolver {
055
056        private final Set<Method> handlerMethods = new LinkedHashSet<Method>();
057
058        private final Set<Method> initBinderMethods = new LinkedHashSet<Method>();
059
060        private final Set<Method> modelAttributeMethods = new LinkedHashSet<Method>();
061
062        private RequestMapping typeLevelMapping;
063
064        private boolean sessionAttributesFound;
065
066        private final Set<String> sessionAttributeNames = new HashSet<String>();
067
068        private final Set<Class<?>> sessionAttributeTypes = new HashSet<Class<?>>();
069
070        private final Set<String> actualSessionAttributeNames =
071                        Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>(4));
072
073
074        /**
075         * Initialize a new HandlerMethodResolver for the specified handler type.
076         * @param handlerType the handler class to introspect
077         */
078        public void init(final Class<?> handlerType) {
079                Set<Class<?>> handlerTypes = new LinkedHashSet<Class<?>>();
080                Class<?> specificHandlerType = null;
081                if (!Proxy.isProxyClass(handlerType)) {
082                        handlerTypes.add(handlerType);
083                        specificHandlerType = handlerType;
084                }
085                handlerTypes.addAll(Arrays.asList(handlerType.getInterfaces()));
086                for (Class<?> currentHandlerType : handlerTypes) {
087                        final Class<?> targetClass = (specificHandlerType != null ? specificHandlerType : currentHandlerType);
088                        ReflectionUtils.doWithMethods(currentHandlerType, new ReflectionUtils.MethodCallback() {
089                                @Override
090                                public void doWith(Method method) {
091                                        Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
092                                        Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
093                                        if (isHandlerMethod(specificMethod) &&
094                                                        (bridgedMethod == specificMethod || !isHandlerMethod(bridgedMethod))) {
095                                                handlerMethods.add(specificMethod);
096                                        }
097                                        else if (isInitBinderMethod(specificMethod) &&
098                                                        (bridgedMethod == specificMethod || !isInitBinderMethod(bridgedMethod))) {
099                                                initBinderMethods.add(specificMethod);
100                                        }
101                                        else if (isModelAttributeMethod(specificMethod) &&
102                                                        (bridgedMethod == specificMethod || !isModelAttributeMethod(bridgedMethod))) {
103                                                modelAttributeMethods.add(specificMethod);
104                                        }
105                                }
106                        }, ReflectionUtils.USER_DECLARED_METHODS);
107                }
108                this.typeLevelMapping = AnnotationUtils.findAnnotation(handlerType, RequestMapping.class);
109                SessionAttributes sessionAttributes = AnnotationUtils.findAnnotation(handlerType, SessionAttributes.class);
110                this.sessionAttributesFound = (sessionAttributes != null);
111                if (this.sessionAttributesFound) {
112                        this.sessionAttributeNames.addAll(Arrays.asList(sessionAttributes.names()));
113                        this.sessionAttributeTypes.addAll(Arrays.asList(sessionAttributes.types()));
114                }
115        }
116
117        protected boolean isHandlerMethod(Method method) {
118                return AnnotationUtils.findAnnotation(method, RequestMapping.class) != null;
119        }
120
121        protected boolean isInitBinderMethod(Method method) {
122                return AnnotationUtils.findAnnotation(method, InitBinder.class) != null;
123        }
124
125        protected boolean isModelAttributeMethod(Method method) {
126                return AnnotationUtils.findAnnotation(method, ModelAttribute.class) != null;
127        }
128
129
130        public final boolean hasHandlerMethods() {
131                return !this.handlerMethods.isEmpty();
132        }
133
134        public final Set<Method> getHandlerMethods() {
135                return this.handlerMethods;
136        }
137
138        public final Set<Method> getInitBinderMethods() {
139                return this.initBinderMethods;
140        }
141
142        public final Set<Method> getModelAttributeMethods() {
143                return this.modelAttributeMethods;
144        }
145
146        public boolean hasTypeLevelMapping() {
147                return (this.typeLevelMapping != null);
148        }
149
150        public RequestMapping getTypeLevelMapping() {
151                return this.typeLevelMapping;
152        }
153
154        public boolean hasSessionAttributes() {
155                return this.sessionAttributesFound;
156        }
157
158        public boolean isSessionAttribute(String attrName, Class<?> attrType) {
159                if (this.sessionAttributeNames.contains(attrName) || this.sessionAttributeTypes.contains(attrType)) {
160                        this.actualSessionAttributeNames.add(attrName);
161                        return true;
162                }
163                else {
164                        return false;
165                }
166        }
167
168        public Set<String> getActualSessionAttributeNames() {
169                return this.actualSessionAttributeNames;
170        }
171
172}