001/* 002 * Copyright 2002-2014 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.servlet.mvc.support; 018 019import java.util.Arrays; 020import java.util.Collections; 021import java.util.HashSet; 022import java.util.Set; 023 024import org.springframework.web.servlet.handler.AbstractDetectingUrlHandlerMapping; 025 026/** 027 * Base class for {@link org.springframework.web.servlet.HandlerMapping} implementations 028 * that derive URL paths according to conventions for specific controller types. 029 * 030 * @author Juergen Hoeller 031 * @since 2.5.3 032 * @see ControllerClassNameHandlerMapping 033 * @see ControllerBeanNameHandlerMapping 034 * @deprecated as of 4.3, in favor of annotation-driven handler methods 035 */ 036@Deprecated 037public abstract class AbstractControllerUrlHandlerMapping extends AbstractDetectingUrlHandlerMapping { 038 039 private ControllerTypePredicate predicate = new AnnotationControllerTypePredicate(); 040 041 private Set<String> excludedPackages = Collections.singleton("org.springframework.web.servlet.mvc"); 042 043 private Set<Class<?>> excludedClasses = Collections.emptySet(); 044 045 046 /** 047 * Set whether to activate or deactivate detection of annotated controllers. 048 */ 049 public void setIncludeAnnotatedControllers(boolean includeAnnotatedControllers) { 050 this.predicate = (includeAnnotatedControllers ? 051 new AnnotationControllerTypePredicate() : new ControllerTypePredicate()); 052 } 053 054 /** 055 * Specify Java packages that should be excluded from this mapping. 056 * Any classes in such a package (or any of its subpackages) will be 057 * ignored by this HandlerMapping. 058 * <p>Default is to exclude the entire "org.springframework.web.servlet.mvc" 059 * package, including its subpackages, since none of Spring's out-of-the-box 060 * Controller implementations is a reasonable candidate for this mapping strategy. 061 * Such controllers are typically handled by a separate HandlerMapping, 062 * e.g. a {@link org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping}, 063 * alongside this ControllerClassNameHandlerMapping for application controllers. 064 */ 065 public void setExcludedPackages(String... excludedPackages) { 066 this.excludedPackages = (excludedPackages != null) ? 067 new HashSet<String>(Arrays.asList(excludedPackages)) : new HashSet<String>(); 068 } 069 070 /** 071 * Specify controller classes that should be excluded from this mapping. 072 * Any such classes will simply be ignored by this HandlerMapping. 073 */ 074 public void setExcludedClasses(Class<?>... excludedClasses) { 075 this.excludedClasses = (excludedClasses != null) ? 076 new HashSet<Class<?>>(Arrays.asList(excludedClasses)) : new HashSet<Class<?>>(); 077 } 078 079 080 /** 081 * This implementation delegates to {@link #buildUrlsForHandler}, 082 * provided that {@link #isEligibleForMapping} returns {@code true}. 083 */ 084 @Override 085 protected String[] determineUrlsForHandler(String beanName) { 086 Class<?> beanClass = getApplicationContext().getType(beanName); 087 if (isEligibleForMapping(beanName, beanClass)) { 088 return buildUrlsForHandler(beanName, beanClass); 089 } 090 else { 091 return null; 092 } 093 } 094 095 /** 096 * Determine whether the specified controller is excluded from this mapping. 097 * @param beanName the name of the controller bean 098 * @param beanClass the concrete class of the controller bean 099 * @return whether the specified class is excluded 100 * @see #setExcludedPackages 101 * @see #setExcludedClasses 102 */ 103 protected boolean isEligibleForMapping(String beanName, Class<?> beanClass) { 104 if (beanClass == null) { 105 if (logger.isDebugEnabled()) { 106 logger.debug("Excluding controller bean '" + beanName + "' from class name mapping " + 107 "because its bean type could not be determined"); 108 } 109 return false; 110 } 111 if (this.excludedClasses.contains(beanClass)) { 112 if (logger.isDebugEnabled()) { 113 logger.debug("Excluding controller bean '" + beanName + "' from class name mapping " + 114 "because its bean class is explicitly excluded: " + beanClass.getName()); 115 } 116 return false; 117 } 118 String beanClassName = beanClass.getName(); 119 for (String packageName : this.excludedPackages) { 120 if (beanClassName.startsWith(packageName)) { 121 if (logger.isDebugEnabled()) { 122 logger.debug("Excluding controller bean '" + beanName + "' from class name mapping " + 123 "because its bean class is defined in an excluded package: " + beanClass.getName()); 124 } 125 return false; 126 } 127 } 128 return isControllerType(beanClass); 129 } 130 131 /** 132 * Determine whether the given bean class indicates a controller type 133 * that is supported by this mapping strategy. 134 * @param beanClass the class to introspect 135 */ 136 protected boolean isControllerType(Class<?> beanClass) { 137 return this.predicate.isControllerType(beanClass); 138 } 139 140 /** 141 * Determine whether the given bean class indicates a controller type 142 * that dispatches to multiple action methods. 143 * @param beanClass the class to introspect 144 */ 145 protected boolean isMultiActionControllerType(Class<?> beanClass) { 146 return this.predicate.isMultiActionControllerType(beanClass); 147 } 148 149 150 /** 151 * Abstract template method to be implemented by subclasses. 152 * @param beanName the name of the bean 153 * @param beanClass the type of the bean 154 * @return the URLs determined for the bean 155 */ 156 protected abstract String[] buildUrlsForHandler(String beanName, Class<?> beanClass); 157 158}