提交 260bbe31 编写于 作者: J Juergen Hoeller

Fixed accidental use of Java 8 getParameterCount(), plus polishing of related classes

Issue: SPR-11245
上级 234272eb
......@@ -18,7 +18,6 @@ package org.springframework.web.method.annotation;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.servlet.ServletException;
import org.springframework.beans.factory.config.BeanExpressionContext;
......@@ -61,8 +60,13 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle
private final BeanExpressionContext expressionContext;
private Map<MethodParameter, NamedValueInfo> namedValueInfoCache =
new ConcurrentHashMap<MethodParameter, NamedValueInfo>(256);
private Map<MethodParameter, NamedValueInfo> namedValueInfoCache = new ConcurrentHashMap<MethodParameter, NamedValueInfo>(256);
public AbstractNamedValueMethodArgumentResolver() {
this.configurableBeanFactory = null;
this.expressionContext = null;
}
/**
* @param beanFactory a bean factory to use for resolving ${...} placeholder
......@@ -71,14 +75,13 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle
*/
public AbstractNamedValueMethodArgumentResolver(ConfigurableBeanFactory beanFactory) {
this.configurableBeanFactory = beanFactory;
this.expressionContext = (beanFactory != null) ? new BeanExpressionContext(beanFactory, new RequestScope()) : null;
this.expressionContext = (beanFactory != null ? new BeanExpressionContext(beanFactory, new RequestScope()) : null);
}
@Override
public final Object resolveArgument(
MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory)
throws Exception {
public final Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
Class<?> paramType = parameter.getParameterType();
NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
......@@ -217,7 +220,7 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle
private final String defaultValue;
protected NamedValueInfo(String name, boolean required, String defaultValue) {
public NamedValueInfo(String name, boolean required, String defaultValue) {
this.name = name;
this.required = required;
this.defaultValue = defaultValue;
......
......@@ -21,7 +21,6 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
......@@ -80,35 +79,45 @@ public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethod
private final boolean useDefaultResolution;
/**
* @param useDefaultResolution in default resolution mode a method argument
* that is a simple type, as defined in {@link BeanUtils#isSimpleProperty},
* is treated as a request parameter even if it it isn't annotated, the
* request parameter name is derived from the method parameter name.
*/
public RequestParamMethodArgumentResolver(boolean useDefaultResolution) {
this.useDefaultResolution = useDefaultResolution;
}
/**
* @param beanFactory a bean factory used for resolving ${...} placeholder
* and #{...} SpEL expressions in default values, or {@code null} if default
* values are not expected to contain expressions
* @param useDefaultResolution in default resolution mode a method argument
* that is a simple type, as defined in {@link BeanUtils#isSimpleProperty},
* is treated as a request parameter even if it itsn't annotated, the
* is treated as a request parameter even if it it isn't annotated, the
* request parameter name is derived from the method parameter name.
*/
public RequestParamMethodArgumentResolver(ConfigurableBeanFactory beanFactory,
boolean useDefaultResolution) {
public RequestParamMethodArgumentResolver(ConfigurableBeanFactory beanFactory, boolean useDefaultResolution) {
super(beanFactory);
this.useDefaultResolution = useDefaultResolution;
}
/**
* Supports the following:
* <ul>
* <li>@RequestParam-annotated method arguments.
* This excludes {@link Map} params where the annotation doesn't
* specify a name. See {@link RequestParamMapMethodArgumentResolver}
* instead for such params.
* <li>Arguments of type {@link MultipartFile}
* unless annotated with @{@link RequestPart}.
* <li>Arguments of type {@code javax.servlet.http.Part}
* unless annotated with @{@link RequestPart}.
* <li>In default resolution mode, simple type arguments
* even if not with @{@link RequestParam}.
* <li>@RequestParam-annotated method arguments.
* This excludes {@link Map} params where the annotation doesn't
* specify a name. See {@link RequestParamMapMethodArgumentResolver}
* instead for such params.
* <li>Arguments of type {@link MultipartFile}
* unless annotated with @{@link RequestPart}.
* <li>Arguments of type {@code javax.servlet.http.Part}
* unless annotated with @{@link RequestPart}.
* <li>In default resolution mode, simple type arguments
* even if not with @{@link RequestParam}.
* </ul>
*/
@Override
......@@ -149,7 +158,6 @@ public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethod
@Override
protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest webRequest) throws Exception {
Object arg;
HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
......@@ -243,9 +251,9 @@ public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethod
builder.queryParam(name);
}
else if (value instanceof Collection) {
for (Object v : (Collection<?>) value) {
v = formatUriValue(conversionService, TypeDescriptor.nested(parameter, 1), v);
builder.queryParam(name, v);
for (Object element : (Collection<?>) value) {
element = formatUriValue(conversionService, TypeDescriptor.nested(parameter, 1), element);
builder.queryParam(name, element);
}
}
else {
......@@ -254,18 +262,17 @@ public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethod
}
protected String formatUriValue(ConversionService cs, TypeDescriptor sourceType, Object value) {
return (cs != null) ?
(String) cs.convert(value, sourceType, STRING_TYPE_DESCRIPTOR) : null;
return (cs != null ? (String) cs.convert(value, sourceType, STRING_TYPE_DESCRIPTOR) : null);
}
private class RequestParamNamedValueInfo extends NamedValueInfo {
private static class RequestParamNamedValueInfo extends NamedValueInfo {
private RequestParamNamedValueInfo() {
public RequestParamNamedValueInfo() {
super("", false, ValueConstants.DEFAULT_NONE);
}
private RequestParamNamedValueInfo(RequestParam annotation) {
public RequestParamNamedValueInfo(RequestParam annotation) {
super(annotation.value(), annotation.required(), annotation.defaultValue());
}
}
......
......@@ -16,17 +16,18 @@
package org.springframework.web.method.support;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.ConversionService;
import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.util.Assert;
import org.springframework.web.util.UriComponentsBuilder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* A {@link UriComponentsContributor} containing a list of other contributors
* to delegate and also encapsulating a specific {@link ConversionService} to
......@@ -37,7 +38,7 @@ import java.util.Map;
*/
public class CompositeUriComponentsContributor implements UriComponentsContributor {
private final List<UriComponentsContributor> contributors = new ArrayList<UriComponentsContributor>();
private final List<UriComponentsContributor> contributors = new LinkedList<UriComponentsContributor>();
private final ConversionService conversionService;
......@@ -46,10 +47,24 @@ public class CompositeUriComponentsContributor implements UriComponentsContribut
* Create an instance from a collection of {@link UriComponentsContributor}s or
* {@link HandlerMethodArgumentResolver}s. Since both of these tend to be implemented
* by the same class, the most convenient option is to obtain the configured
* {@code HandlerMethodArgumentResolvers} in {@code RequestMappingHandlerAdapter} and
* provide that to this constructor.
* {@code HandlerMethodArgumentResolvers} in {@code RequestMappingHandlerAdapter}
* and provide that to this constructor.
* @param contributors a collection of {@link UriComponentsContributor}
* or {@link HandlerMethodArgumentResolver}s.
* or {@link HandlerMethodArgumentResolver}s.
*/
public CompositeUriComponentsContributor(UriComponentsContributor... contributors) {
Collections.addAll(this.contributors, contributors);
this.conversionService = new DefaultFormattingConversionService();
}
/**
* Create an instance from a collection of {@link UriComponentsContributor}s or
* {@link HandlerMethodArgumentResolver}s. Since both of these tend to be implemented
* by the same class, the most convenient option is to obtain the configured
* {@code HandlerMethodArgumentResolvers} in {@code RequestMappingHandlerAdapter}
* and provide that to this constructor.
* @param contributors a collection of {@link UriComponentsContributor}
* or {@link HandlerMethodArgumentResolver}s.
*/
public CompositeUriComponentsContributor(Collection<?> contributors) {
this(contributors, null);
......@@ -70,17 +85,14 @@ public class CompositeUriComponentsContributor implements UriComponentsContribut
* need to be formatted as Strings before being added to the URI
*/
public CompositeUriComponentsContributor(Collection<?> contributors, ConversionService conversionService) {
Assert.notNull(contributors, "'uriComponentsContributors' must not be null");
for (Object contributor : contributors) {
if (contributor instanceof UriComponentsContributor) {
this.contributors.add((UriComponentsContributor) contributor);
}
}
this.conversionService = (conversionService != null) ?
conversionService : new DefaultFormattingConversionService();
this.conversionService =
(conversionService != null ? conversionService : new DefaultFormattingConversionService());
}
......@@ -90,8 +102,8 @@ public class CompositeUriComponentsContributor implements UriComponentsContribut
@Override
public boolean supportsParameter(MethodParameter parameter) {
for (UriComponentsContributor c : this.contributors) {
if (c.supportsParameter(parameter)) {
for (UriComponentsContributor contributor : this.contributors) {
if (contributor.supportsParameter(parameter)) {
return true;
}
}
......@@ -102,9 +114,9 @@ public class CompositeUriComponentsContributor implements UriComponentsContribut
public void contributeMethodArgument(MethodParameter parameter, Object value,
UriComponentsBuilder builder, Map<String, Object> uriVariables, ConversionService conversionService) {
for (UriComponentsContributor c : this.contributors) {
if (c.supportsParameter(parameter)) {
c.contributeMethodArgument(parameter, value, builder, uriVariables, conversionService);
for (UriComponentsContributor contributor : this.contributors) {
if (contributor.supportsParameter(parameter)) {
contributor.contributeMethodArgument(parameter, value, builder, uriVariables, conversionService);
break;
}
}
......
......@@ -16,9 +16,16 @@
package org.springframework.web.servlet.mvc.method.annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.aopalliance.intercept.MethodInterceptor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.target.EmptyTargetSource;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
......@@ -31,7 +38,12 @@ import org.springframework.core.MethodParameter;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.objenesis.ObjenesisStd;
import org.springframework.util.*;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.PathMatcher;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestAttributes;
......@@ -44,17 +56,12 @@ import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.*;
/**
* A UriComponentsBuilder that helps to build URIs to Spring MVC controllers and methods from their
* request mappings.
* A UriComponentsBuilder that helps to build URIs to Spring MVC controllers
* and methods from their request mappings.
*
* @author Oliver Gierke
* @author Rossen Stoyanchev
*
* @since 4.0
*/
public class MvcUriComponentsBuilder extends UriComponentsBuilder {
......@@ -71,16 +78,14 @@ public class MvcUriComponentsBuilder extends UriComponentsBuilder {
private static final ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
private final static ObjenesisStd objenesis = new ObjenesisStd(true);
private static final ObjenesisStd objenesis = new ObjenesisStd(true);
private static Log logger = LogFactory.getLog(MvcUriComponentsBuilder.class);
private static final Log logger = LogFactory.getLog(MvcUriComponentsBuilder.class);
static {
defaultUriComponentsContributor = new CompositeUriComponentsContributor(
Arrays.<Object> asList(
new PathVariableMethodArgumentResolver(),
new RequestParamMethodArgumentResolver(null, false)));
new PathVariableMethodArgumentResolver(), new RequestParamMethodArgumentResolver(false));
}
......@@ -113,23 +118,20 @@ public class MvcUriComponentsBuilder extends UriComponentsBuilder {
* @param argumentValues argument values matching to method parameters
* @return a UriComponentsBuilder instance
*/
public static UriComponentsBuilder fromMethodName(Class<?> controllerType,
String methodName, Object... argumentValues) {
public static UriComponentsBuilder fromMethodName(Class<?> controllerType, String methodName, Object... argumentValues) {
Method match = null;
for (Method method : controllerType.getDeclaredMethods()) {
if ((method.getParameterCount() == argumentValues.length) && method.getName().equals(methodName)) {
if (method.getName().equals(methodName) && method.getParameterTypes().length == argumentValues.length) {
if (match != null) {
throw new IllegalStateException("Found two methods named '" + methodName
+ "' having " + argumentValues + " arguments, controller "
+ controllerType.getName());
throw new IllegalStateException("Found two methods named '" + methodName + "' having " +
Arrays.asList(argumentValues) + " arguments, controller " + controllerType.getName());
}
match = method;
}
}
if (match == null) {
throw new IllegalArgumentException("No method '" + methodName + "' with "
+ argumentValues.length + " parameters found in " + controllerType.getName());
throw new IllegalArgumentException("No method '" + methodName + "' with " + argumentValues.length +
" parameters found in " + controllerType.getName());
}
return fromMethod(match, argumentValues);
}
......@@ -147,7 +149,6 @@ public class MvcUriComponentsBuilder extends UriComponentsBuilder {
* @return a UriComponentsBuilder instance
*/
public static UriComponentsBuilder fromMethod(Method method, Object... argumentValues) {
UriComponentsBuilder builder = ServletUriComponentsBuilder.newInstance().path(getMethodRequestMapping(method));
UriComponents uriComponents = applyContributors(builder, method, argumentValues);
......@@ -155,15 +156,13 @@ public class MvcUriComponentsBuilder extends UriComponentsBuilder {
String methodPath = uriComponents.getPath();
String path = pathMatcher.combine(typePath, methodPath);
return ServletUriComponentsBuilder.fromCurrentServletMapping().path(
path).queryParams(uriComponents.getQueryParams());
return ServletUriComponentsBuilder.fromCurrentServletMapping().path(path).queryParams(uriComponents.getQueryParams());
}
/**
* Create a {@link UriComponents} by invoking a method on a "mock" controller, similar
* to how test frameworks provide mock objects and record method invocations.
* <p>For example given this controller:
*
* <pre class="code">
* &#064;RequestMapping("/people/{id}/addresses")
* class AddressController {
......@@ -175,11 +174,8 @@ public class MvcUriComponentsBuilder extends UriComponentsBuilder {
* public void addAddress(Address address) { ... }
* }
* </pre>
*
* A "mock" controller can be used as follows:
*
* <pre>
*
* <pre class="code">
* // Inline style with static import of MvcUriComponentsBuilder.mock
*
* MvcUriComponentsBuilder.fromMethodCall(
......@@ -191,9 +187,7 @@ public class MvcUriComponentsBuilder extends UriComponentsBuilder {
* controller.addAddress(null);
*
* MvcUriComponentsBuilder.fromMethodCall(controller);
*
* </pre>
*
* The above supports {@code @PathVariable} and {@code @RequestParam} method parameters.
* Any other arguments can be provided as {@literal null} and will be ignored.
* <p>Additional (custom) argument types can be supported through an implementation
......@@ -203,7 +197,6 @@ public class MvcUriComponentsBuilder extends UriComponentsBuilder {
* @return a UriComponents instance
*/
public static UriComponentsBuilder fromMethodCall(Object methodInvocationInfo) {
Assert.isInstanceOf(MethodInvocationInfo.class, methodInvocationInfo);
MethodInvocationInfo info = (MethodInvocationInfo) methodInvocationInfo;
......@@ -217,8 +210,7 @@ public class MvcUriComponentsBuilder extends UriComponentsBuilder {
String methodMapping = uriComponents.getPath();
String path = pathMatcher.combine(typeMapping, methodMapping);
return ServletUriComponentsBuilder.fromCurrentServletMapping().path(
path).queryParams(uriComponents.getQueryParams());
return ServletUriComponentsBuilder.fromCurrentServletMapping().path(path).queryParams(uriComponents.getQueryParams());
}
......@@ -247,7 +239,6 @@ public class MvcUriComponentsBuilder extends UriComponentsBuilder {
}
private static UriComponents applyContributors(UriComponentsBuilder builder, Method method, Object[] args) {
CompositeUriComponentsContributor contributor = getConfiguredUriComponentsContributor();
if (contributor == null) {
logger.debug("Using default CompositeUriComponentsContributor");
......@@ -256,18 +247,15 @@ public class MvcUriComponentsBuilder extends UriComponentsBuilder {
int paramCount = method.getParameterTypes().length;
int argCount = args.length;
Assert.isTrue(paramCount == argCount, "Number of method parameters " + paramCount +
" does not match number of argument values " + argCount);
Map<String, Object> uriVars = new HashMap<String, Object>();
for (int i=0; i < paramCount; i++) {
MethodParameter param = new MethodParameter(method, i);
param.initParameterNameDiscovery(parameterNameDiscoverer);
contributor.contributeMethodArgument(param, args[i], builder, uriVars);
}
return builder.buildAndExpand(uriVars);
}
......@@ -294,8 +282,8 @@ public class MvcUriComponentsBuilder extends UriComponentsBuilder {
}
catch (NoSuchBeanDefinitionException ex) {
if (logger.isDebugEnabled()) {
logger.debug("No CompositeUriComponentsContributor bean with name '"
+ MVC_URI_COMPONENTS_CONTRIBUTOR_BEAN_NAME + "'");
logger.debug("No CompositeUriComponentsContributor bean with name '" +
MVC_URI_COMPONENTS_CONTRIBUTOR_BEAN_NAME + "'");
}
return null;
}
......@@ -308,7 +296,7 @@ public class MvcUriComponentsBuilder extends UriComponentsBuilder {
* {@link #fromMethodCall(Object)}.
* <p>This is a shorthand version of {@link #controller(Class)} intended for
* inline use as follows:
* <pre>
* <pre class="code">
* UriComponentsBuilder builder = MvcUriComponentsBuilder.fromMethodCall(
* on(FooController.class).getFoo(1)).build();
* </pre>
......@@ -325,7 +313,7 @@ public class MvcUriComponentsBuilder extends UriComponentsBuilder {
* {@link #fromMethodCall(Object)}.
* <p>This is a longer version of {@link #on(Class)} for use with void controller
* methods as well as for creating multiple links in succession.
* <pre>
* <pre class="code">
* FooController fooController = controller(FooController.class);
*
* fooController.saveFoo(1, null);
......@@ -343,7 +331,6 @@ public class MvcUriComponentsBuilder extends UriComponentsBuilder {
@SuppressWarnings("unchecked")
private static <T> T initProxy(Class<?> type, ControllerMethodInvocationInterceptor interceptor) {
if (type.isInterface()) {
ProxyFactory factory = new ProxyFactory(EmptyTargetSource.INSTANCE);
factory.addInterface(type);
......@@ -356,9 +343,8 @@ public class MvcUriComponentsBuilder extends UriComponentsBuilder {
enhancer.setSuperclass(type);
enhancer.setInterfaces(new Class<?>[]{MethodInvocationInfo.class});
enhancer.setCallbackType(org.springframework.cglib.proxy.MethodInterceptor.class);
Factory factory = (Factory) objenesis.newInstance(enhancer.createClass());
factory.setCallbacks(new Callback[] { interceptor });
factory.setCallbacks(new Callback[] {interceptor});
return (T) factory;
}
}
......@@ -373,15 +359,12 @@ public class MvcUriComponentsBuilder extends UriComponentsBuilder {
private static final Method getArgumentValues =
ReflectionUtils.findMethod(MethodInvocationInfo.class, "getArgumentValues");
private Method controllerMethod;
private Object[] argumentValues;
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) {
if (getControllerMethod.equals(method)) {
return this.controllerMethod;
}
......@@ -394,9 +377,8 @@ public class MvcUriComponentsBuilder extends UriComponentsBuilder {
else {
this.controllerMethod = method;
this.argumentValues = args;
Class<?> returnType = method.getReturnType();
return void.class.equals(returnType) ? null : returnType.cast(initProxy(returnType, this));
return (void.class.equals(returnType) ? null : returnType.cast(initProxy(returnType, this)));
}
}
......@@ -406,12 +388,12 @@ public class MvcUriComponentsBuilder extends UriComponentsBuilder {
}
}
public interface MethodInvocationInfo {
Method getControllerMethod();
Object[] getArgumentValues();
}
}
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -56,8 +56,8 @@ import org.springframework.web.util.UriComponentsBuilder;
* {@link RequestParamMapMethodArgumentResolver} is used instead to provide
* access to all URI variables in a map.
*
* <p>A {@link WebDataBinder} is invoked to apply type conversion to resolved path variable values that
* don't yet match the method parameter type.
* <p>A {@link WebDataBinder} is invoked to apply type conversion to resolved
* path variable values that don't yet match the method parameter type.
*
* @author Rossen Stoyanchev
* @author Arjen Poutsma
......@@ -70,9 +70,9 @@ public class PathVariableMethodArgumentResolver extends AbstractNamedValueMethod
public PathVariableMethodArgumentResolver() {
super(null);
}
@Override
public boolean supportsParameter(MethodParameter parameter) {
if (!parameter.hasParameterAnnotation(PathVariable.class)) {
......@@ -143,8 +143,9 @@ public class PathVariableMethodArgumentResolver extends AbstractNamedValueMethod
private static class PathVariableNamedValueInfo extends NamedValueInfo {
private PathVariableNamedValueInfo(PathVariable annotation) {
public PathVariableNamedValueInfo(PathVariable annotation) {
super(annotation.value(), true, ValueConstants.DEFAULT_NONE);
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册