diff --git a/spring-core/src/main/java/org/springframework/core/MethodParameter.java b/spring-core/src/main/java/org/springframework/core/MethodParameter.java index 6a0137aa57..19c397e627 100644 --- a/spring-core/src/main/java/org/springframework/core/MethodParameter.java +++ b/spring-core/src/main/java/org/springframework/core/MethodParameter.java @@ -26,7 +26,6 @@ import java.lang.reflect.Type; import java.util.HashMap; import java.util.Map; -import org.springframework.core.annotation.AnnotationUtils; import org.springframework.util.Assert; /** @@ -34,6 +33,10 @@ import org.springframework.util.Assert; * a Method or Constructor plus a parameter index and a nested type index for * a declared generic type. Useful as a specification object to pass along. * + *

As of 4.2, there is a {@link org.springframework.core.annotation.SynthesizingMethodParameter} + * subclass available which synthesizes annotations based on overridden annotation attributes. + * That subclass is being used for web and message endpoint processing, in particular. + * * @author Juergen Hoeller * @author Rob Harrop * @author Andy Clement @@ -388,7 +391,7 @@ public class MethodParameter { * Return the annotations associated with the target method/constructor itself. */ public Annotation[] getMethodAnnotations() { - return AnnotationUtils.synthesizeAnnotationArray(getAnnotatedElement().getAnnotations(), getAnnotatedElement()); + return adaptAnnotationArray(getAnnotatedElement().getAnnotations()); } /** @@ -396,9 +399,8 @@ public class MethodParameter { * @param annotationType the annotation type to look for * @return the annotation object, or {@code null} if not found */ - public T getMethodAnnotation(Class annotationType) { - AnnotatedElement element = getAnnotatedElement(); - return AnnotationUtils.synthesizeAnnotation(element.getAnnotation(annotationType), element); + public A getMethodAnnotation(Class annotationType) { + return adaptAnnotation(getAnnotatedElement().getAnnotation(annotationType)); } /** @@ -409,8 +411,7 @@ public class MethodParameter { Annotation[][] annotationArray = (this.method != null ? this.method.getParameterAnnotations() : this.constructor.getParameterAnnotations()); if (this.parameterIndex >= 0 && this.parameterIndex < annotationArray.length) { - this.parameterAnnotations = AnnotationUtils.synthesizeAnnotationArray( - annotationArray[this.parameterIndex], getAnnotatedElement()); + this.parameterAnnotations = adaptAnnotationArray(annotationArray[this.parameterIndex]); } else { this.parameterAnnotations = new Annotation[0]; @@ -480,6 +481,31 @@ public class MethodParameter { } + /** + * A template method to post-process a given annotation instance before + * returning it to the caller. + *

The default implementation simply returns the given annotation as-is. + * @param annotation the annotation about to be returned + * @return the post-processed annotation (or simply the original one) + * @since 4.2 + */ + protected A adaptAnnotation(A annotation) { + return annotation; + } + + /** + * A template method to post-process a given annotation array before + * returning it to the caller. + *

The default implementation simply returns the given annotation array as-is. + * @param annotations the annotation array about to be returned + * @return the post-processed annotation array (or simply the original one) + * @since 4.2 + */ + protected Annotation[] adaptAnnotationArray(Annotation[] annotations) { + return annotations; + } + + @Override public boolean equals(Object other) { if (this == other) { diff --git a/spring-core/src/main/java/org/springframework/core/ResolvableType.java b/spring-core/src/main/java/org/springframework/core/ResolvableType.java index 8432d75569..d52cfa5498 100644 --- a/spring-core/src/main/java/org/springframework/core/ResolvableType.java +++ b/spring-core/src/main/java/org/springframework/core/ResolvableType.java @@ -1122,7 +1122,7 @@ public class ResolvableType implements Serializable { */ public static ResolvableType forMethodReturnType(Method method) { Assert.notNull(method, "Method must not be null"); - return forMethodParameter(MethodParameter.forMethodOrConstructor(method, -1)); + return forMethodParameter(new MethodParameter(method, -1)); } /** @@ -1136,7 +1136,7 @@ public class ResolvableType implements Serializable { */ public static ResolvableType forMethodReturnType(Method method, Class implementationClass) { Assert.notNull(method, "Method must not be null"); - MethodParameter methodParameter = MethodParameter.forMethodOrConstructor(method, -1); + MethodParameter methodParameter = new MethodParameter(method, -1); methodParameter.setContainingClass(implementationClass); return forMethodParameter(methodParameter); } diff --git a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java index 030fc45268..b42818a03d 100644 --- a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java +++ b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java @@ -266,6 +266,7 @@ public abstract class AnnotationUtils { @Deprecated public static Set getRepeatableAnnotation(Method method, Class containerAnnotationType, Class annotationType) { + return getRepeatableAnnotations(method, annotationType, containerAnnotationType); } @@ -280,6 +281,7 @@ public abstract class AnnotationUtils { @Deprecated public static Set getRepeatableAnnotation(AnnotatedElement annotatedElement, Class containerAnnotationType, Class annotationType) { + return getRepeatableAnnotations(annotatedElement, annotationType, containerAnnotationType); } @@ -311,6 +313,7 @@ public abstract class AnnotationUtils { */ public static Set getRepeatableAnnotations(AnnotatedElement annotatedElement, Class annotationType) { + return getRepeatableAnnotations(annotatedElement, annotationType, null); } @@ -353,7 +356,7 @@ public abstract class AnnotationUtils { if (annotatedElement instanceof Class) { Class superclass = ((Class) annotatedElement).getSuperclass(); - if ((superclass != null) && (Object.class != superclass)) { + if (superclass != null && Object.class != superclass) { return getRepeatableAnnotations(superclass, annotationType, containerAnnotationType); } } @@ -434,7 +437,6 @@ public abstract class AnnotationUtils { * compiler if the supplied element is a {@link Method}. *

Meta-annotations will be searched if the annotation is not * present on the supplied element. - * * @param annotatedElement the element to look for annotations on; never {@code null} * @param annotationType the annotation type to look for; never {@code null} * @param containerAnnotationType the type of the container that holds @@ -955,10 +957,8 @@ public abstract class AnnotationUtils { /** * Retrieve the given annotation's attributes as an {@link AnnotationAttributes} map. - * *

This method provides fully recursive annotation reading capabilities on par with * the reflection-based {@link org.springframework.core.type.StandardAnnotationMetadata}. - * *

NOTE: This variant of {@code getAnnotationAttributes()} is * only intended for use within the framework. Specifically, the {@code mergeMode} flag * can be set to {@code true} in order to support processing of attribute aliases while @@ -975,7 +975,6 @@ public abstract class AnnotationUtils { * ensure that placeholders have been replaced by actual default values and * in order to enforce {@code @AliasFor} semantics. * - * * @param annotatedElement the element that is annotated with the supplied annotation; * may be {@code null} if unknown * @param annotation the annotation to retrieve the attributes for @@ -1062,8 +1061,7 @@ public abstract class AnnotationUtils { Annotation annotation = (Annotation) value; if (nestedAnnotationsAsMap) { - return getAnnotationAttributes(annotatedElement, annotation, classValuesAsString, - nestedAnnotationsAsMap); + return getAnnotationAttributes(annotatedElement, annotation, classValuesAsString, true); } else { return synthesizeAnnotation(annotation, annotatedElement); @@ -1077,7 +1075,7 @@ public abstract class AnnotationUtils { AnnotationAttributes[] mappedAnnotations = new AnnotationAttributes[annotations.length]; for (int i = 0; i < annotations.length; i++) { mappedAnnotations[i] = getAnnotationAttributes(annotatedElement, annotations[i], - classValuesAsString, nestedAnnotationsAsMap); + classValuesAsString, true); } return mappedAnnotations; } @@ -1183,7 +1181,6 @@ public abstract class AnnotationUtils { * by wrapping it in a dynamic proxy that transparently enforces * attribute alias semantics for annotation attributes that are * annotated with {@link AliasFor @AliasFor}. - * * @param annotation the annotation to synthesize * @return the synthesized annotation, if the supplied annotation is * synthesizable; {@code null} if the supplied annotation is @@ -1202,7 +1199,6 @@ public abstract class AnnotationUtils { * by wrapping it in a dynamic proxy that transparently enforces * attribute alias semantics for annotation attributes that are * annotated with {@link AliasFor @AliasFor}. - * * @param annotation the annotation to synthesize * @param annotatedElement the element that is annotated with the supplied * annotation; may be {@code null} if unknown @@ -1229,11 +1225,11 @@ public abstract class AnnotationUtils { return annotation; } - AnnotationAttributeExtractor attributeExtractor = new DefaultAnnotationAttributeExtractor(annotation, - annotatedElement); + AnnotationAttributeExtractor attributeExtractor = + new DefaultAnnotationAttributeExtractor(annotation, annotatedElement); InvocationHandler handler = new SynthesizedAnnotationInvocationHandler(attributeExtractor); - A synthesizedAnnotation = (A) Proxy.newProxyInstance(ClassUtils.getDefaultClassLoader(), new Class[] { - (Class) annotationType, SynthesizedAnnotation.class }, handler); + A synthesizedAnnotation = (A) Proxy.newProxyInstance(ClassUtils.getDefaultClassLoader(), + new Class[] {(Class) annotationType, SynthesizedAnnotation.class}, handler); return synthesizedAnnotation; } @@ -1250,7 +1246,6 @@ public abstract class AnnotationUtils { *

Note that {@link AnnotationAttributes} is a specialized type of * {@link Map} that is an ideal candidate for this method's * {@code attributes} argument. - * * @param attributes the map of annotation attributes to synthesize * @param annotationType the type of annotation to synthesize; never {@code null} * @param annotatedElement the element that is annotated with the annotation @@ -1268,17 +1263,17 @@ public abstract class AnnotationUtils { @SuppressWarnings("unchecked") public static A synthesizeAnnotation(Map attributes, Class annotationType, AnnotatedElement annotatedElement) { - Assert.notNull(annotationType, "annotationType must not be null"); + Assert.notNull(annotationType, "annotationType must not be null"); if (attributes == null) { return null; } - AnnotationAttributeExtractor attributeExtractor = new MapAnnotationAttributeExtractor(attributes, - annotationType, annotatedElement); + AnnotationAttributeExtractor attributeExtractor = + new MapAnnotationAttributeExtractor(attributes, annotationType, annotatedElement); InvocationHandler handler = new SynthesizedAnnotationInvocationHandler(attributeExtractor); - A synthesizedAnnotation = (A) Proxy.newProxyInstance(ClassUtils.getDefaultClassLoader(), new Class[] { - annotationType, SynthesizedAnnotation.class }, handler); + A synthesizedAnnotation = (A) Proxy.newProxyInstance(ClassUtils.getDefaultClassLoader(), + new Class[] {annotationType, SynthesizedAnnotation.class}, handler); return synthesizedAnnotation; } @@ -1289,7 +1284,6 @@ public abstract class AnnotationUtils { * {@link #synthesizeAnnotation(Map, Class, AnnotatedElement)}, * supplying an empty map for the source attribute values and {@code null} * for the {@link AnnotatedElement}. - * * @param annotationType the type of annotation to synthesize; never {@code null} * @return the synthesized annotation * @throws IllegalArgumentException if a required attribute is missing @@ -1308,7 +1302,6 @@ public abstract class AnnotationUtils { * creating a new array of the same size and type and populating it * with {@linkplain #synthesizeAnnotation(Annotation) synthesized} * versions of the annotations from the input array. - * * @param annotations the array of annotations to synthesize * @param annotatedElement the element that is annotated with the supplied * array of annotations; may be {@code null} if unknown @@ -1325,7 +1318,8 @@ public abstract class AnnotationUtils { return null; } - Annotation[] synthesized = (Annotation[]) Array.newInstance(annotations.getClass().getComponentType(), annotations.length); + Annotation[] synthesized = (Annotation[]) Array.newInstance( + annotations.getClass().getComponentType(), annotations.length); for (int i = 0; i < annotations.length; i++) { synthesized[i] = synthesizeAnnotation(annotations[i], annotatedElement); } @@ -1335,14 +1329,11 @@ public abstract class AnnotationUtils { /** * Get a map of all attribute alias pairs, declared via {@code @AliasFor} * in the supplied annotation type. - * *

The map is keyed by attribute name with each value representing * the name of the aliased attribute. For each entry {@code [x, y]} in * the map there will be a corresponding {@code [y, x]} entry in the map. - * *

An empty return value implies that the annotation does not declare * any attribute aliases. - * * @param annotationType the annotation type to find attribute aliases in * @return a map containing attribute alias pairs; never {@code null} * @since 4.2 @@ -1376,34 +1367,28 @@ public abstract class AnnotationUtils { * synthesizable (i.e., in need of being wrapped in a dynamic * proxy that provides functionality above that of a standard JDK * annotation). - * *

Specifically, an annotation is synthesizable if it declares * any attributes that are configured as aliased pairs via * {@link AliasFor @AliasFor} or if any nested annotations used by the * annotation declare such aliased pairs. - * * @since 4.2 * @see SynthesizedAnnotation * @see SynthesizedAnnotationInvocationHandler */ @SuppressWarnings("unchecked") private static boolean isSynthesizable(Class annotationType) { - Boolean synthesizable = synthesizableCache.get(annotationType); if (synthesizable != null) { return synthesizable.booleanValue(); } synthesizable = Boolean.FALSE; - for (Method attribute : getAttributeMethods(annotationType)) { if (getAliasedAttributeName(attribute) != null) { synthesizable = Boolean.TRUE; break; } - Class returnType = attribute.getReturnType(); - if (Annotation[].class.isAssignableFrom(returnType)) { Class nestedAnnotationType = (Class) returnType.getComponentType(); if (isSynthesizable(nestedAnnotationType)) { @@ -1421,20 +1406,17 @@ public abstract class AnnotationUtils { } synthesizableCache.put(annotationType, synthesizable); - return synthesizable.booleanValue(); } /** * Get the name of the aliased attribute configured via * {@link AliasFor @AliasFor} on the supplied annotation {@code attribute}. - * *

This method does not resolve aliases in other annotations. In * other words, if {@code @AliasFor} is present on the supplied * {@code attribute} but {@linkplain AliasFor#annotation references an * annotation} other than {@link Annotation}, this method will return * {@code null} immediately. - * * @param attribute the attribute to find an alias for * @return the name of the aliased attribute, or {@code null} if not found * @throws IllegalArgumentException if the supplied attribute method is @@ -1451,7 +1433,6 @@ public abstract class AnnotationUtils { /** * Get the name of the aliased attribute configured via * {@link AliasFor @AliasFor} on the supplied annotation {@code attribute}. - * * @param attribute the attribute to find an alias for * @param targetAnnotationType the type of annotation in which the * aliased attribute is allowed to be declared; {@code null} implies @@ -1481,7 +1462,8 @@ public abstract class AnnotationUtils { Class aliasedAnnotationType = aliasFor.annotation(); boolean searchWithinSameAnnotation = (targetAnnotationType == null); - boolean sameTargetDeclared = (sourceAnnotationType.equals(aliasedAnnotationType) || Annotation.class.equals(aliasedAnnotationType)); + boolean sameTargetDeclared = + (sourceAnnotationType.equals(aliasedAnnotationType) || Annotation.class.equals(aliasedAnnotationType)); // Wrong search scope? if (searchWithinSameAnnotation && !sameTargetDeclared) { @@ -1502,30 +1484,30 @@ public abstract class AnnotationUtils { aliasedAnnotationType = sourceAnnotationType; } - Method aliasedAttribute = null; + Method aliasedAttribute; try { aliasedAttribute = aliasedAnnotationType.getDeclaredMethod(aliasedAttributeName); } - catch (NoSuchMethodException e) { + catch (NoSuchMethodException ex) { String msg = String.format( - "Attribute [%s] in annotation [%s] is declared as an @AliasFor nonexistent attribute [%s] in annotation [%s].", - attributeName, sourceAnnotationType.getName(), aliasedAttributeName, aliasedAnnotationType.getName()); - throw new AnnotationConfigurationException(msg, e); + "Attribute [%s] in annotation [%s] is declared as an @AliasFor nonexistent attribute [%s] in annotation [%s].", + attributeName, sourceAnnotationType.getName(), aliasedAttributeName, aliasedAnnotationType.getName()); + throw new AnnotationConfigurationException(msg, ex); } if (sameTargetDeclared) { AliasFor mirrorAliasFor = aliasedAttribute.getAnnotation(AliasFor.class); if (mirrorAliasFor == null) { String msg = String.format("Attribute [%s] in annotation [%s] must be declared as an @AliasFor [%s].", - aliasedAttributeName, sourceAnnotationType.getName(), attributeName); + aliasedAttributeName, sourceAnnotationType.getName(), attributeName); throw new AnnotationConfigurationException(msg); } String mirrorAliasedAttributeName = mirrorAliasFor.attribute(); if (!attributeName.equals(mirrorAliasedAttributeName)) { String msg = String.format( - "Attribute [%s] in annotation [%s] must be declared as an @AliasFor [%s], not [%s].", - aliasedAttributeName, sourceAnnotationType.getName(), attributeName, mirrorAliasedAttributeName); + "Attribute [%s] in annotation [%s] must be declared as an @AliasFor [%s], not [%s].", + aliasedAttributeName, sourceAnnotationType.getName(), attributeName, mirrorAliasedAttributeName); throw new AnnotationConfigurationException(msg); } } @@ -1533,9 +1515,9 @@ public abstract class AnnotationUtils { Class returnType = attribute.getReturnType(); Class aliasedReturnType = aliasedAttribute.getReturnType(); if (!returnType.equals(aliasedReturnType)) { - String msg = String.format("Misconfigured aliases: attribute [%s] in annotation [%s] " - + "and attribute [%s] in annotation [%s] must declare the same return type.", attributeName, - sourceAnnotationType.getName(), aliasedAttributeName, aliasedAnnotationType.getName()); + String msg = String.format("Misconfigured aliases: attribute [%s] in annotation [%s] " + + "and attribute [%s] in annotation [%s] must declare the same return type.", attributeName, + sourceAnnotationType.getName(), aliasedAttributeName, aliasedAnnotationType.getName()); throw new AnnotationConfigurationException(msg); } @@ -1544,16 +1526,16 @@ public abstract class AnnotationUtils { Object aliasedDefaultValue = aliasedAttribute.getDefaultValue(); if ((defaultValue == null) || (aliasedDefaultValue == null)) { - String msg = String.format("Misconfigured aliases: attribute [%s] in annotation [%s] " - + "and attribute [%s] in annotation [%s] must declare default values.", attributeName, - sourceAnnotationType.getName(), aliasedAttributeName, aliasedAnnotationType.getName()); + String msg = String.format("Misconfigured aliases: attribute [%s] in annotation [%s] " + + "and attribute [%s] in annotation [%s] must declare default values.", attributeName, + sourceAnnotationType.getName(), aliasedAttributeName, aliasedAnnotationType.getName()); throw new AnnotationConfigurationException(msg); } if (!ObjectUtils.nullSafeEquals(defaultValue, aliasedDefaultValue)) { - String msg = String.format("Misconfigured aliases: attribute [%s] in annotation [%s] " - + "and attribute [%s] in annotation [%s] must declare the same default value.", attributeName, - sourceAnnotationType.getName(), aliasedAttributeName, aliasedAnnotationType.getName()); + String msg = String.format("Misconfigured aliases: attribute [%s] in annotation [%s] " + + "and attribute [%s] in annotation [%s] must declare the same default value.", attributeName, + sourceAnnotationType.getName(), aliasedAttributeName, aliasedAnnotationType.getName()); throw new AnnotationConfigurationException(msg); } } @@ -1564,10 +1546,8 @@ public abstract class AnnotationUtils { /** * Get all methods declared in the supplied {@code annotationType} that * match Java's requirements for annotation attributes. - * *

All methods in the returned list will be * {@linkplain ReflectionUtils#makeAccessible(Method) made accessible}. - * * @param annotationType the type in which to search for attribute methods; * never {@code null} * @return all annotation attribute methods in the specified annotation @@ -1575,7 +1555,6 @@ public abstract class AnnotationUtils { * @since 4.2 */ static List getAttributeMethods(Class annotationType) { - List methods = attributeMethodsCache.get(annotationType); if (methods != null) { return methods; @@ -1590,7 +1569,6 @@ public abstract class AnnotationUtils { } attributeMethodsCache.put(annotationType, methods); - return methods; } @@ -1618,7 +1596,7 @@ public abstract class AnnotationUtils { * @return {@code true} if the method is an attribute method */ static boolean isAttributeMethod(Method method) { - return ((method != null) && (method.getParameterTypes().length == 0) && (method.getReturnType() != void.class)); + return (method != null && method.getParameterTypes().length == 0 && method.getReturnType() != void.class); } /** @@ -1627,17 +1605,15 @@ public abstract class AnnotationUtils { * @see Annotation#annotationType() */ static boolean isAnnotationTypeMethod(Method method) { - return ((method != null) && method.getName().equals("annotationType") && (method.getParameterTypes().length == 0)); + return (method != null && method.getName().equals("annotationType") && method.getParameterTypes().length == 0); } /** * Post-process the supplied {@link AnnotationAttributes}. - * *

Specifically, this method enforces attribute alias semantics * for annotation attributes that are annotated with {@link AliasFor @AliasFor} * and replaces {@linkplain #DEFAULT_VALUE_PLACEHOLDER placeholders} with their * original default values. - * * @param element the element that is annotated with an annotation or * annotation hierarchy from which the supplied attributes were created; * may be {@code null} if unknown @@ -1715,9 +1691,9 @@ public abstract class AnnotationUtils { * @param t the throwable to inspect * @since 4.2 */ - static void rethrowAnnotationConfigurationException(Throwable t) { - if (t instanceof AnnotationConfigurationException) { - throw (AnnotationConfigurationException) t; + static void rethrowAnnotationConfigurationException(Throwable ex) { + if (ex instanceof AnnotationConfigurationException) { + throw (AnnotationConfigurationException) ex; } } @@ -1731,13 +1707,11 @@ public abstract class AnnotationUtils { * Class values were not resolvable within annotation attributes and * thereby effectively pretending there were no annotations on the specified * element. - * * @param element the element that we tried to introspect annotations on * @param ex the exception that we encountered * @see #rethrowAnnotationConfigurationException */ static void handleIntrospectionFailure(AnnotatedElement element, Exception ex) { - rethrowAnnotationConfigurationException(ex); Log loggerToUse = logger; @@ -1745,7 +1719,7 @@ public abstract class AnnotationUtils { loggerToUse = LogFactory.getLog(AnnotationUtils.class); logger = loggerToUse; } - if ((element instanceof Class) && Annotation.class.isAssignableFrom((Class) element)) { + if (element instanceof Class && Annotation.class.isAssignableFrom((Class) element)) { // Meta-annotation lookup on an annotation type if (loggerToUse.isDebugEnabled()) { loggerToUse.debug("Failed to introspect meta-annotations on [" + element + "]: " + ex); @@ -1798,7 +1772,6 @@ public abstract class AnnotationUtils { private static final String REPEATABLE_CLASS_NAME = "java.lang.annotation.Repeatable"; - private final Class annotationType; private final Class containerAnnotationType; @@ -1809,17 +1782,13 @@ public abstract class AnnotationUtils { private final Set result = new LinkedHashSet(); - AnnotationCollector(Class annotationType, Class containerAnnotationType, boolean declaredMode) { this.annotationType = annotationType; - this.containerAnnotationType = (containerAnnotationType != null ? containerAnnotationType - : resolveContainerAnnotationType(annotationType)); + this.containerAnnotationType = (containerAnnotationType != null ? containerAnnotationType : + resolveContainerAnnotationType(annotationType)); this.declaredMode = declaredMode; } - /** - * @since 4.2 - */ @SuppressWarnings("unchecked") static Class resolveContainerAnnotationType(Class annotationType) { try { @@ -1829,8 +1798,8 @@ public abstract class AnnotationUtils { return (Class) value; } } - catch (Exception e) { - handleIntrospectionFailure(annotationType, e); + catch (Exception ex) { + handleIntrospectionFailure(annotationType, ex); } return null; } diff --git a/spring-core/src/main/java/org/springframework/core/annotation/SynthesizingMethodParameter.java b/spring-core/src/main/java/org/springframework/core/annotation/SynthesizingMethodParameter.java new file mode 100644 index 0000000000..af26f0a345 --- /dev/null +++ b/spring-core/src/main/java/org/springframework/core/annotation/SynthesizingMethodParameter.java @@ -0,0 +1,59 @@ +/* + * Copyright 2002-2015 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core.annotation; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; + +import org.springframework.core.MethodParameter; + +/** + * A {@link MethodParameter} variant which synthesizes annotations + * based on overridden annotation attributes, e.g. as declared with + * {@link AliasFor @AliasFor}. + * + * @author Juergen Hoeller + * @author Sam Brannen + * @since 4.2 + * @see AnnotationUtils#synthesizeAnnotation + * @see AnnotationUtils#synthesizeAnnotationArray + */ +public class SynthesizingMethodParameter extends MethodParameter { + + /** + * Create a new {@code SynthesizingMethodParameter} for the given method. + * @param method the Method to specify a parameter for + * @param parameterIndex the index of the parameter: -1 for the method + * return type; 0 for the first method parameter; 1 for the second method + * parameter, etc. + */ + public SynthesizingMethodParameter(Method method, int parameterIndex) { + super(method, parameterIndex); + } + + + @Override + protected A adaptAnnotation(A annotation) { + return AnnotationUtils.synthesizeAnnotation(annotation, getAnnotatedElement()); + } + + @Override + protected Annotation[] adaptAnnotationArray(Annotation[] annotations) { + return AnnotationUtils.synthesizeAnnotationArray(annotations, getAnnotatedElement()); + } + +} diff --git a/spring-messaging/src/main/java/org/springframework/messaging/handler/HandlerMethod.java b/spring-messaging/src/main/java/org/springframework/messaging/handler/HandlerMethod.java index 33538c2976..b7898d3ef4 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/handler/HandlerMethod.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/handler/HandlerMethod.java @@ -26,6 +26,7 @@ import org.springframework.beans.factory.BeanFactory; import org.springframework.core.BridgeMethodResolver; import org.springframework.core.MethodParameter; import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.core.annotation.SynthesizingMethodParameter; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -258,7 +259,7 @@ public class HandlerMethod { /** * A MethodParameter with HandlerMethod-specific behavior. */ - protected class HandlerMethodParameter extends MethodParameter { + protected class HandlerMethodParameter extends SynthesizingMethodParameter { public HandlerMethodParameter(int index) { super(HandlerMethod.this.bridgedMethod, index); diff --git a/spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/HeaderMethodArgumentResolverTests.java b/spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/HeaderMethodArgumentResolverTests.java index 6985c9eb48..429b5ce8ac 100644 --- a/spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/HeaderMethodArgumentResolverTests.java +++ b/spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/HeaderMethodArgumentResolverTests.java @@ -27,6 +27,7 @@ import org.springframework.context.support.GenericApplicationContext; import org.springframework.core.DefaultParameterNameDiscoverer; import org.springframework.core.GenericTypeResolver; import org.springframework.core.MethodParameter; +import org.springframework.core.annotation.SynthesizingMethodParameter; import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.messaging.Message; import org.springframework.messaging.MessageHandlingException; @@ -62,16 +63,17 @@ public class HeaderMethodArgumentResolverTests { Method method = getClass().getDeclaredMethod("handleMessage", String.class, String.class, String.class, String.class, String.class); - this.paramRequired = new MethodParameter(method, 0); - this.paramNamedDefaultValueStringHeader = new MethodParameter(method, 1); - this.paramSystemProperty = new MethodParameter(method, 2); - this.paramNotAnnotated = new MethodParameter(method, 3); - this.paramNativeHeader = new MethodParameter(method, 4); + this.paramRequired = new SynthesizingMethodParameter(method, 0); + this.paramNamedDefaultValueStringHeader = new SynthesizingMethodParameter(method, 1); + this.paramSystemProperty = new SynthesizingMethodParameter(method, 2); + this.paramNotAnnotated = new SynthesizingMethodParameter(method, 3); + this.paramNativeHeader = new SynthesizingMethodParameter(method, 4); this.paramRequired.initParameterNameDiscovery(new DefaultParameterNameDiscoverer()); GenericTypeResolver.resolveParameterType(this.paramRequired, HeaderMethodArgumentResolver.class); } + @Test public void supportsParameter() { assertTrue(resolver.supportsParameter(paramNamedDefaultValueStringHeader)); diff --git a/spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/PayloadArgumentResolverTests.java b/spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/PayloadArgumentResolverTests.java index 2c40b6b465..ffc0954109 100644 --- a/spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/PayloadArgumentResolverTests.java +++ b/spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/PayloadArgumentResolverTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2015 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. @@ -30,12 +30,12 @@ import org.junit.rules.ExpectedException; import org.springframework.core.LocalVariableTableParameterNameDiscoverer; import org.springframework.core.MethodParameter; +import org.springframework.core.annotation.SynthesizingMethodParameter; import org.springframework.messaging.Message; import org.springframework.messaging.converter.MessageConversionException; import org.springframework.messaging.converter.StringMessageConverter; import org.springframework.messaging.handler.annotation.Payload; import org.springframework.messaging.support.MessageBuilder; -import org.springframework.util.Assert; import org.springframework.validation.Errors; import org.springframework.validation.Validator; import org.springframework.validation.annotation.Validated; @@ -80,14 +80,14 @@ public class PayloadArgumentResolverTests { this.payloadMethod = PayloadArgumentResolverTests.class.getDeclaredMethod("handleMessage", String.class, String.class, Locale.class, String.class, String.class, String.class, String.class); - this.paramAnnotated = getMethodParameter(this.payloadMethod, 0); - this.paramAnnotatedNotRequired = getMethodParameter(this.payloadMethod, 1); - this.paramAnnotatedRequired = getMethodParameter(payloadMethod, 2); - this.paramWithSpelExpression = getMethodParameter(payloadMethod, 3); - this.paramValidated = getMethodParameter(this.payloadMethod, 4); + this.paramAnnotated = new SynthesizingMethodParameter(this.payloadMethod, 0); + this.paramAnnotatedNotRequired = new SynthesizingMethodParameter(this.payloadMethod, 1); + this.paramAnnotatedRequired = new SynthesizingMethodParameter(payloadMethod, 2); + this.paramWithSpelExpression = new SynthesizingMethodParameter(payloadMethod, 3); + this.paramValidated = new SynthesizingMethodParameter(this.payloadMethod, 4); this.paramValidated.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer()); - this.paramValidatedNotAnnotated = getMethodParameter(this.payloadMethod, 5); - this.paramNotAnnotated = getMethodParameter(this.payloadMethod, 6); + this.paramValidatedNotAnnotated = new SynthesizingMethodParameter(this.payloadMethod, 5); + this.paramNotAnnotated = new SynthesizingMethodParameter(this.payloadMethod, 6); } @@ -204,10 +204,6 @@ public class PayloadArgumentResolverTests { }; } - private MethodParameter getMethodParameter(Method method, int index) { - Assert.notNull(method, "Method must be set"); - return new MethodParameter(method, index); - } @SuppressWarnings("unused") private void handleMessage( diff --git a/spring-messaging/src/test/java/org/springframework/messaging/simp/annotation/support/SendToMethodReturnValueHandlerTests.java b/spring-messaging/src/test/java/org/springframework/messaging/simp/annotation/support/SendToMethodReturnValueHandlerTests.java index eec2255405..78a2bb02be 100644 --- a/spring-messaging/src/test/java/org/springframework/messaging/simp/annotation/support/SendToMethodReturnValueHandlerTests.java +++ b/spring-messaging/src/test/java/org/springframework/messaging/simp/annotation/support/SendToMethodReturnValueHandlerTests.java @@ -16,20 +16,17 @@ package org.springframework.messaging.simp.annotation.support; -import com.fasterxml.jackson.annotation.JsonView; - import java.lang.reflect.Method; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.security.Principal; import java.util.LinkedHashMap; import java.util.Map; - import javax.security.auth.Subject; +import com.fasterxml.jackson.annotation.JsonView; import org.junit.Before; import org.junit.Test; - import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; @@ -37,6 +34,7 @@ import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.springframework.core.MethodParameter; +import org.springframework.core.annotation.SynthesizingMethodParameter; import org.springframework.messaging.Message; import org.springframework.messaging.MessageChannel; import org.springframework.messaging.MessageHeaders; @@ -56,7 +54,7 @@ import org.springframework.util.MimeType; import static org.junit.Assert.*; import static org.mockito.BDDMockito.*; -import static org.springframework.messaging.handler.annotation.support.DestinationVariableMethodArgumentResolver.DESTINATION_TEMPLATE_VARIABLES_HEADER; +import static org.springframework.messaging.handler.annotation.support.DestinationVariableMethodArgumentResolver.*; import static org.springframework.messaging.support.MessageHeaderAccessor.*; /** @@ -95,7 +93,6 @@ public class SendToMethodReturnValueHandlerTests { @Before public void setup() throws Exception { - MockitoAnnotations.initMocks(this); SimpMessagingTemplate messagingTemplate = new SimpMessagingTemplate(this.messageChannel); @@ -108,31 +105,31 @@ public class SendToMethodReturnValueHandlerTests { this.jsonHandler = new SendToMethodReturnValueHandler(jsonMessagingTemplate, true); Method method = this.getClass().getDeclaredMethod("handleNoAnnotations"); - this.noAnnotationsReturnType = new MethodParameter(method, -1); + this.noAnnotationsReturnType = new SynthesizingMethodParameter(method, -1); method = this.getClass().getDeclaredMethod("handleAndSendToDefaultDestination"); - this.sendToDefaultDestReturnType = new MethodParameter(method, -1); + this.sendToDefaultDestReturnType = new SynthesizingMethodParameter(method, -1); method = this.getClass().getDeclaredMethod("handleAndSendTo"); - this.sendToReturnType = new MethodParameter(method, -1); + this.sendToReturnType = new SynthesizingMethodParameter(method, -1); method = this.getClass().getDeclaredMethod("handleAndSendToWithPlaceholders"); - this.sendToWithPlaceholdersReturnType = new MethodParameter(method, -1); + this.sendToWithPlaceholdersReturnType = new SynthesizingMethodParameter(method, -1); method = this.getClass().getDeclaredMethod("handleAndSendToUser"); - this.sendToUserReturnType = new MethodParameter(method, -1); + this.sendToUserReturnType = new SynthesizingMethodParameter(method, -1); method = this.getClass().getDeclaredMethod("handleAndSendToUserSingleSession"); - this.sendToUserSingleSessionReturnType = new MethodParameter(method, -1); + this.sendToUserSingleSessionReturnType = new SynthesizingMethodParameter(method, -1); method = this.getClass().getDeclaredMethod("handleAndSendToUserDefaultDestination"); - this.sendToUserDefaultDestReturnType = new MethodParameter(method, -1); + this.sendToUserDefaultDestReturnType = new SynthesizingMethodParameter(method, -1); method = this.getClass().getDeclaredMethod("handleAndSendToUserDefaultDestinationSingleSession"); - this.sendToUserSingleSessionDefaultDestReturnType = new MethodParameter(method, -1); + this.sendToUserSingleSessionDefaultDestReturnType = new SynthesizingMethodParameter(method, -1); method = this.getClass().getDeclaredMethod("handleAndSendToJsonView"); - this.jsonViewReturnType = new MethodParameter(method, -1); + this.jsonViewReturnType = new SynthesizingMethodParameter(method, -1); } diff --git a/spring-web/src/main/java/org/springframework/web/bind/annotation/support/HandlerMethodInvoker.java b/spring-web/src/main/java/org/springframework/web/bind/annotation/support/HandlerMethodInvoker.java index ff66d18c9b..eb8693338c 100644 --- a/spring-web/src/main/java/org/springframework/web/bind/annotation/support/HandlerMethodInvoker.java +++ b/spring-web/src/main/java/org/springframework/web/bind/annotation/support/HandlerMethodInvoker.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2015 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. @@ -43,6 +43,7 @@ import org.springframework.core.GenericTypeResolver; import org.springframework.core.MethodParameter; import org.springframework.core.ParameterNameDiscoverer; import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.core.annotation.SynthesizingMethodParameter; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpInputMessage; @@ -241,7 +242,7 @@ public class HandlerMethodInvoker { Object[] args = new Object[paramTypes.length]; for (int i = 0; i < args.length; i++) { - MethodParameter methodParam = new MethodParameter(handlerMethod, i); + MethodParameter methodParam = new SynthesizingMethodParameter(handlerMethod, i); methodParam.initParameterNameDiscovery(this.parameterNameDiscoverer); GenericTypeResolver.resolveParameterType(methodParam, handler.getClass()); String paramName = null; @@ -420,7 +421,7 @@ public class HandlerMethodInvoker { Object[] initBinderArgs = new Object[initBinderParams.length]; for (int i = 0; i < initBinderArgs.length; i++) { - MethodParameter methodParam = new MethodParameter(initBinderMethod, i); + MethodParameter methodParam = new SynthesizingMethodParameter(initBinderMethod, i); methodParam.initParameterNameDiscovery(this.parameterNameDiscoverer); GenericTypeResolver.resolveParameterType(methodParam, handler.getClass()); String paramName = null; diff --git a/spring-web/src/main/java/org/springframework/web/method/HandlerMethod.java b/spring-web/src/main/java/org/springframework/web/method/HandlerMethod.java index 6905dce959..5be84c0077 100644 --- a/spring-web/src/main/java/org/springframework/web/method/HandlerMethod.java +++ b/spring-web/src/main/java/org/springframework/web/method/HandlerMethod.java @@ -26,6 +26,7 @@ import org.springframework.beans.factory.BeanFactory; import org.springframework.core.BridgeMethodResolver; import org.springframework.core.MethodParameter; import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.core.annotation.SynthesizingMethodParameter; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -268,7 +269,7 @@ public class HandlerMethod { /** * A MethodParameter with HandlerMethod-specific behavior. */ - protected class HandlerMethodParameter extends MethodParameter { + protected class HandlerMethodParameter extends SynthesizingMethodParameter { public HandlerMethodParameter(int index) { super(HandlerMethod.this.bridgedMethod, index); diff --git a/spring-web/src/main/java/org/springframework/web/method/annotation/RequestHeaderMethodArgumentResolver.java b/spring-web/src/main/java/org/springframework/web/method/annotation/RequestHeaderMethodArgumentResolver.java index c209c52c06..3ef1b4fea8 100644 --- a/spring-web/src/main/java/org/springframework/web/method/annotation/RequestHeaderMethodArgumentResolver.java +++ b/spring-web/src/main/java/org/springframework/web/method/annotation/RequestHeaderMethodArgumentResolver.java @@ -55,8 +55,8 @@ public class RequestHeaderMethodArgumentResolver extends AbstractNamedValueMetho @Override public boolean supportsParameter(MethodParameter parameter) { - return parameter.hasParameterAnnotation(RequestHeader.class) && - !Map.class.isAssignableFrom(parameter.getParameterType()); + return (parameter.hasParameterAnnotation(RequestHeader.class) && + !Map.class.isAssignableFrom(parameter.getParameterType())); } @Override diff --git a/spring-web/src/main/java/org/springframework/web/method/support/CompositeUriComponentsContributor.java b/spring-web/src/main/java/org/springframework/web/method/support/CompositeUriComponentsContributor.java index f061d86ed2..1df794a7c5 100644 --- a/spring-web/src/main/java/org/springframework/web/method/support/CompositeUriComponentsContributor.java +++ b/spring-web/src/main/java/org/springframework/web/method/support/CompositeUriComponentsContributor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2015 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. @@ -117,16 +117,16 @@ public class CompositeUriComponentsContributor implements UriComponentsContribut public void contributeMethodArgument(MethodParameter parameter, Object value, UriComponentsBuilder builder, Map uriVariables, ConversionService conversionService) { - for (Object c : this.contributors) { - if (c instanceof UriComponentsContributor) { - UriComponentsContributor contributor = (UriComponentsContributor) c; - if (contributor.supportsParameter(parameter)) { - contributor.contributeMethodArgument(parameter, value, builder, uriVariables, conversionService); + for (Object contributor : this.contributors) { + if (contributor instanceof UriComponentsContributor) { + UriComponentsContributor ucc = (UriComponentsContributor) contributor; + if (ucc.supportsParameter(parameter)) { + ucc.contributeMethodArgument(parameter, value, builder, uriVariables, conversionService); break; } } - else if (c instanceof HandlerMethodArgumentResolver) { - if (((HandlerMethodArgumentResolver) c).supportsParameter(parameter)) { + else if (contributor instanceof HandlerMethodArgumentResolver) { + if (((HandlerMethodArgumentResolver) contributor).supportsParameter(parameter)) { break; } } diff --git a/spring-web/src/test/java/org/springframework/web/method/annotation/CookieValueMethodArgumentResolverTests.java b/spring-web/src/test/java/org/springframework/web/method/annotation/CookieValueMethodArgumentResolverTests.java index 0181b63a5d..e1f9929a73 100644 --- a/spring-web/src/test/java/org/springframework/web/method/annotation/CookieValueMethodArgumentResolverTests.java +++ b/spring-web/src/test/java/org/springframework/web/method/annotation/CookieValueMethodArgumentResolverTests.java @@ -23,6 +23,7 @@ import org.junit.Before; import org.junit.Test; import org.springframework.core.MethodParameter; +import org.springframework.core.annotation.SynthesizingMethodParameter; import org.springframework.mock.web.test.MockHttpServletRequest; import org.springframework.mock.web.test.MockHttpServletResponse; import org.springframework.web.bind.ServletRequestBindingException; @@ -52,19 +53,21 @@ public class CookieValueMethodArgumentResolverTests { private MockHttpServletRequest request; + @Before public void setUp() throws Exception { resolver = new TestCookieValueMethodArgumentResolver(); Method method = getClass().getMethod("params", Cookie.class, String.class, String.class); - paramNamedCookie = new MethodParameter(method, 0); - paramNamedDefaultValueString = new MethodParameter(method, 1); - paramString = new MethodParameter(method, 2); + paramNamedCookie = new SynthesizingMethodParameter(method, 0); + paramNamedDefaultValueString = new SynthesizingMethodParameter(method, 1); + paramString = new SynthesizingMethodParameter(method, 2); request = new MockHttpServletRequest(); webRequest = new ServletWebRequest(request, new MockHttpServletResponse()); } + @Test public void supportsParameter() { assertTrue("Cookie parameter not supported", resolver.supportsParameter(paramNamedCookie)); @@ -98,9 +101,10 @@ public class CookieValueMethodArgumentResolverTests { } } + public void params(@CookieValue("name") Cookie param1, @CookieValue(name = "name", defaultValue = "bar") String param2, String param3) { } -} \ No newline at end of file +} diff --git a/spring-web/src/test/java/org/springframework/web/method/annotation/RequestHeaderMapMethodArgumentResolverTests.java b/spring-web/src/test/java/org/springframework/web/method/annotation/RequestHeaderMapMethodArgumentResolverTests.java index e86446ddee..ef2a3f0183 100644 --- a/spring-web/src/test/java/org/springframework/web/method/annotation/RequestHeaderMapMethodArgumentResolverTests.java +++ b/spring-web/src/test/java/org/springframework/web/method/annotation/RequestHeaderMapMethodArgumentResolverTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2015 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. @@ -24,6 +24,7 @@ import org.junit.Before; import org.junit.Test; import org.springframework.core.MethodParameter; +import org.springframework.core.annotation.SynthesizingMethodParameter; import org.springframework.http.HttpHeaders; import org.springframework.mock.web.test.MockHttpServletRequest; import org.springframework.mock.web.test.MockHttpServletResponse; @@ -57,20 +58,22 @@ public class RequestHeaderMapMethodArgumentResolverTests { private MockHttpServletRequest request; + @Before public void setUp() throws Exception { resolver = new RequestHeaderMapMethodArgumentResolver(); Method method = getClass().getMethod("params", Map.class, MultiValueMap.class, HttpHeaders.class, Map.class); - paramMap = new MethodParameter(method, 0); - paramMultiValueMap = new MethodParameter(method, 1); - paramHttpHeaders = new MethodParameter(method, 2); - paramUnsupported = new MethodParameter(method, 3); + paramMap = new SynthesizingMethodParameter(method, 0); + paramMultiValueMap = new SynthesizingMethodParameter(method, 1); + paramHttpHeaders = new SynthesizingMethodParameter(method, 2); + paramUnsupported = new SynthesizingMethodParameter(method, 3); request = new MockHttpServletRequest(); webRequest = new ServletWebRequest(request, new MockHttpServletResponse()); } + @Test public void supportsParameter() { assertTrue("Map parameter not supported", resolver.supportsParameter(paramMap)); @@ -130,10 +133,11 @@ public class RequestHeaderMapMethodArgumentResolverTests { assertEquals("Invalid result", expected, result); } + public void params(@RequestHeader Map param1, @RequestHeader MultiValueMap param2, @RequestHeader HttpHeaders param3, Map unsupported) { } -} \ No newline at end of file +} diff --git a/spring-web/src/test/java/org/springframework/web/method/annotation/RequestHeaderMethodArgumentResolverTests.java b/spring-web/src/test/java/org/springframework/web/method/annotation/RequestHeaderMethodArgumentResolverTests.java index 0895749867..ecf30430ee 100644 --- a/spring-web/src/test/java/org/springframework/web/method/annotation/RequestHeaderMethodArgumentResolverTests.java +++ b/spring-web/src/test/java/org/springframework/web/method/annotation/RequestHeaderMethodArgumentResolverTests.java @@ -24,6 +24,7 @@ import org.junit.Before; import org.junit.Test; import org.springframework.core.MethodParameter; +import org.springframework.core.annotation.SynthesizingMethodParameter; import org.springframework.mock.web.test.MockHttpServletRequest; import org.springframework.mock.web.test.MockHttpServletResponse; import org.springframework.web.bind.ServletRequestBindingException; @@ -55,6 +56,7 @@ public class RequestHeaderMethodArgumentResolverTests { private NativeWebRequest webRequest; + @Before public void setUp() throws Exception { GenericWebApplicationContext context = new GenericWebApplicationContext(); @@ -62,11 +64,11 @@ public class RequestHeaderMethodArgumentResolverTests { resolver = new RequestHeaderMethodArgumentResolver(context.getBeanFactory()); Method method = getClass().getMethod("params", String.class, String[].class, String.class, String.class, Map.class); - paramNamedDefaultValueStringHeader = new MethodParameter(method, 0); - paramNamedValueStringArray = new MethodParameter(method, 1); - paramSystemProperty = new MethodParameter(method, 2); - paramContextPath = new MethodParameter(method, 3); - paramNamedValueMap = new MethodParameter(method, 4); + paramNamedDefaultValueStringHeader = new SynthesizingMethodParameter(method, 0); + paramNamedValueStringArray = new SynthesizingMethodParameter(method, 1); + paramSystemProperty = new SynthesizingMethodParameter(method, 2); + paramContextPath = new SynthesizingMethodParameter(method, 3); + paramNamedValueMap = new SynthesizingMethodParameter(method, 4); servletRequest = new MockHttpServletRequest(); webRequest = new ServletWebRequest(servletRequest, new MockHttpServletResponse()); @@ -80,6 +82,7 @@ public class RequestHeaderMethodArgumentResolverTests { RequestContextHolder.resetRequestAttributes(); } + @Test public void supportsParameter() { assertTrue("String parameter not supported", resolver.supportsParameter(paramNamedDefaultValueStringHeader)); @@ -141,6 +144,7 @@ public class RequestHeaderMethodArgumentResolverTests { resolver.resolveArgument(paramNamedValueStringArray, null, webRequest, null); } + public void params(@RequestHeader(name = "name", defaultValue = "bar") String param1, @RequestHeader("name") String[] param2, @RequestHeader(name = "name", defaultValue="#{systemProperties.systemProperty}") String param3, @@ -148,4 +152,4 @@ public class RequestHeaderMethodArgumentResolverTests { @RequestHeader("name") Map unsupported) { } -} \ No newline at end of file +} diff --git a/spring-web/src/test/java/org/springframework/web/method/annotation/RequestParamMapMethodArgumentResolverTests.java b/spring-web/src/test/java/org/springframework/web/method/annotation/RequestParamMapMethodArgumentResolverTests.java index 1aa9d371f8..cae73f460d 100644 --- a/spring-web/src/test/java/org/springframework/web/method/annotation/RequestParamMapMethodArgumentResolverTests.java +++ b/spring-web/src/test/java/org/springframework/web/method/annotation/RequestParamMapMethodArgumentResolverTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2015 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. @@ -24,6 +24,7 @@ import org.junit.Before; import org.junit.Test; import org.springframework.core.MethodParameter; +import org.springframework.core.annotation.SynthesizingMethodParameter; import org.springframework.mock.web.test.MockHttpServletRequest; import org.springframework.mock.web.test.MockHttpServletResponse; import org.springframework.util.LinkedMultiValueMap; @@ -56,20 +57,22 @@ public class RequestParamMapMethodArgumentResolverTests { private MockHttpServletRequest request; + @Before public void setUp() throws Exception { resolver = new RequestParamMapMethodArgumentResolver(); Method method = getClass().getMethod("params", Map.class, MultiValueMap.class, Map.class, Map.class); - paramMap = new MethodParameter(method, 0); - paramMultiValueMap = new MethodParameter(method, 1); - paramNamedMap = new MethodParameter(method, 2); - paramMapWithoutAnnot = new MethodParameter(method, 3); + paramMap = new SynthesizingMethodParameter(method, 0); + paramMultiValueMap = new SynthesizingMethodParameter(method, 1); + paramNamedMap = new SynthesizingMethodParameter(method, 2); + paramMapWithoutAnnot = new SynthesizingMethodParameter(method, 3); request = new MockHttpServletRequest(); webRequest = new ServletWebRequest(request, new MockHttpServletResponse()); } + @Test public void supportsParameter() { assertTrue("Map parameter not supported", resolver.supportsParameter(paramMap)); @@ -108,10 +111,11 @@ public class RequestParamMapMethodArgumentResolverTests { assertEquals("Invalid result", expected, result); } + public void params(@RequestParam Map param1, @RequestParam MultiValueMap param2, @RequestParam("name") Map param3, Map param4) { } -} \ No newline at end of file +} diff --git a/spring-web/src/test/java/org/springframework/web/method/annotation/RequestParamMethodArgumentResolverTests.java b/spring-web/src/test/java/org/springframework/web/method/annotation/RequestParamMethodArgumentResolverTests.java index 926ede0ebb..4617715a8c 100644 --- a/spring-web/src/test/java/org/springframework/web/method/annotation/RequestParamMethodArgumentResolverTests.java +++ b/spring-web/src/test/java/org/springframework/web/method/annotation/RequestParamMethodArgumentResolverTests.java @@ -21,7 +21,6 @@ import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Optional; - import javax.servlet.http.Part; import org.junit.Before; @@ -31,6 +30,7 @@ import org.springframework.beans.propertyeditors.StringTrimmerEditor; import org.springframework.core.LocalVariableTableParameterNameDiscoverer; import org.springframework.core.MethodParameter; import org.springframework.core.ParameterNameDiscoverer; +import org.springframework.core.annotation.SynthesizingMethodParameter; import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.mock.web.test.MockHttpServletRequest; import org.springframework.mock.web.test.MockHttpServletResponse; @@ -99,28 +99,28 @@ public class RequestParamMethodArgumentResolverTests { String.class, MultipartFile.class, List.class, Part.class, MultipartFile.class, String.class, String.class, Optional.class); - paramNamedDefaultValueString = new MethodParameter(method, 0); - paramNamedStringArray = new MethodParameter(method, 1); - paramNamedMap = new MethodParameter(method, 2); - paramMultipartFile = new MethodParameter(method, 3); - paramMultipartFileList = new MethodParameter(method, 4); - paramMultipartFileArray = new MethodParameter(method, 5); - paramPart = new MethodParameter(method, 6); - paramPartList = new MethodParameter(method, 7); - paramPartArray = new MethodParameter(method, 8); - paramMap = new MethodParameter(method, 9); - paramStringNotAnnot = new MethodParameter(method, 10); + paramNamedDefaultValueString = new SynthesizingMethodParameter(method, 0); + paramNamedStringArray = new SynthesizingMethodParameter(method, 1); + paramNamedMap = new SynthesizingMethodParameter(method, 2); + paramMultipartFile = new SynthesizingMethodParameter(method, 3); + paramMultipartFileList = new SynthesizingMethodParameter(method, 4); + paramMultipartFileArray = new SynthesizingMethodParameter(method, 5); + paramPart = new SynthesizingMethodParameter(method, 6); + paramPartList = new SynthesizingMethodParameter(method, 7); + paramPartArray = new SynthesizingMethodParameter(method, 8); + paramMap = new SynthesizingMethodParameter(method, 9); + paramStringNotAnnot = new SynthesizingMethodParameter(method, 10); paramStringNotAnnot.initParameterNameDiscovery(paramNameDiscoverer); - paramMultipartFileNotAnnot = new MethodParameter(method, 11); + paramMultipartFileNotAnnot = new SynthesizingMethodParameter(method, 11); paramMultipartFileNotAnnot.initParameterNameDiscovery(paramNameDiscoverer); - paramMultipartFileListNotAnnot = new MethodParameter(method, 12); + paramMultipartFileListNotAnnot = new SynthesizingMethodParameter(method, 12); paramMultipartFileListNotAnnot.initParameterNameDiscovery(paramNameDiscoverer); - paramPartNotAnnot = new MethodParameter(method, 13); + paramPartNotAnnot = new SynthesizingMethodParameter(method, 13); paramPartNotAnnot.initParameterNameDiscovery(paramNameDiscoverer); - paramRequestPartAnnot = new MethodParameter(method, 14); - paramRequired = new MethodParameter(method, 15); - paramNotRequired = new MethodParameter(method, 16); - paramOptional = new MethodParameter(method, 17); + paramRequestPartAnnot = new SynthesizingMethodParameter(method, 14); + paramRequired = new SynthesizingMethodParameter(method, 15); + paramNotRequired = new SynthesizingMethodParameter(method, 16); + paramOptional = new SynthesizingMethodParameter(method, 17); request = new MockHttpServletRequest(); webRequest = new ServletWebRequest(request, new MockHttpServletResponse()); diff --git a/spring-webmvc-portlet/src/main/java/org/springframework/web/portlet/mvc/annotation/AnnotationMethodHandlerExceptionResolver.java b/spring-webmvc-portlet/src/main/java/org/springframework/web/portlet/mvc/annotation/AnnotationMethodHandlerExceptionResolver.java index 0764dd0d44..31e1b86db5 100644 --- a/spring-webmvc-portlet/src/main/java/org/springframework/web/portlet/mvc/annotation/AnnotationMethodHandlerExceptionResolver.java +++ b/spring-webmvc-portlet/src/main/java/org/springframework/web/portlet/mvc/annotation/AnnotationMethodHandlerExceptionResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2015 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. @@ -49,6 +49,7 @@ import org.springframework.core.ExceptionDepthComparator; import org.springframework.core.GenericTypeResolver; import org.springframework.core.MethodParameter; import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.core.annotation.SynthesizingMethodParameter; import org.springframework.ui.Model; import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; @@ -233,7 +234,7 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc Object[] args = new Object[paramTypes.length]; Class handlerType = handler.getClass(); for (int i = 0; i < args.length; i++) { - MethodParameter methodParam = new MethodParameter(handlerMethod, i); + MethodParameter methodParam = new SynthesizingMethodParameter(handlerMethod, i); GenericTypeResolver.resolveParameterType(methodParam, handlerType); Class paramType = methodParam.getParameterType(); Object argValue = resolveCommonArgument(methodParam, webRequest, thrownException); diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerExceptionResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerExceptionResolver.java index 8c82389246..ab26750443 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerExceptionResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerExceptionResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2015 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. @@ -44,6 +44,7 @@ import org.springframework.core.ExceptionDepthComparator; import org.springframework.core.GenericTypeResolver; import org.springframework.core.MethodParameter; import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.core.annotation.SynthesizingMethodParameter; import org.springframework.http.HttpInputMessage; import org.springframework.http.HttpOutputMessage; import org.springframework.http.HttpStatus; @@ -258,7 +259,7 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc Object[] args = new Object[paramTypes.length]; Class handlerType = handler.getClass(); for (int i = 0; i < args.length; i++) { - MethodParameter methodParam = new MethodParameter(handlerMethod, i); + MethodParameter methodParam = new SynthesizingMethodParameter(handlerMethod, i); GenericTypeResolver.resolveParameterType(methodParam, handlerType); Class paramType = methodParam.getParameterType(); Object argValue = resolveCommonArgument(methodParam, webRequest, thrownException); diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilder.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilder.java index 3c5dd8a5d8..85b4bc3549 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilder.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilder.java @@ -41,6 +41,7 @@ import org.springframework.core.DefaultParameterNameDiscoverer; import org.springframework.core.MethodParameter; import org.springframework.core.ParameterNameDiscoverer; import org.springframework.core.annotation.AnnotatedElementUtils; +import org.springframework.core.annotation.SynthesizingMethodParameter; import org.springframework.objenesis.ObjenesisException; import org.springframework.objenesis.SpringObjenesis; import org.springframework.util.AntPathMatcher; @@ -486,7 +487,7 @@ public class MvcUriComponentsBuilder { final Map uriVars = new HashMap(); for (int i = 0; i < paramCount; i++) { - MethodParameter param = new MethodParameter(method, i); + MethodParameter param = new SynthesizingMethodParameter(method, i); param.initParameterNameDiscovery(parameterNameDiscoverer); contributor.contributeMethodArgument(param, args[i], builder, uriVars); } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestPartMethodArgumentResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestPartMethodArgumentResolver.java index 09068e9d2b..59d59d8f99 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestPartMethodArgumentResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestPartMethodArgumentResolver.java @@ -75,7 +75,6 @@ import org.springframework.web.util.WebUtils; */ public class RequestPartMethodArgumentResolver extends AbstractMessageConverterMethodArgumentResolver { - /** * Basic constructor with converters only. */ diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/MatrixVariablesMapMethodArgumentResolverTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/MatrixVariablesMapMethodArgumentResolverTests.java index 6dabf42716..f4fe3ac364 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/MatrixVariablesMapMethodArgumentResolverTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/MatrixVariablesMapMethodArgumentResolverTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2015 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. @@ -26,6 +26,7 @@ import org.junit.Before; import org.junit.Test; import org.springframework.core.MethodParameter; +import org.springframework.core.annotation.SynthesizingMethodParameter; import org.springframework.mock.web.test.MockHttpServletRequest; import org.springframework.mock.web.test.MockHttpServletResponse; import org.springframework.util.LinkedMultiValueMap; @@ -66,11 +67,11 @@ public class MatrixVariablesMapMethodArgumentResolverTests { Method method = getClass().getMethod("handle", String.class, Map.class, MultiValueMap.class, MultiValueMap.class, Map.class); - this.paramString = new MethodParameter(method, 0); - this.paramMap = new MethodParameter(method, 1); - this.paramMultivalueMap = new MethodParameter(method, 2); - this.paramMapForPathVar = new MethodParameter(method, 3); - this.paramMapWithName = new MethodParameter(method, 4); + this.paramString = new SynthesizingMethodParameter(method, 0); + this.paramMap = new SynthesizingMethodParameter(method, 1); + this.paramMultivalueMap = new SynthesizingMethodParameter(method, 2); + this.paramMapForPathVar = new SynthesizingMethodParameter(method, 3); + this.paramMapWithName = new SynthesizingMethodParameter(method, 4); this.mavContainer = new ModelAndViewContainer(); this.request = new MockHttpServletRequest(); @@ -91,7 +92,6 @@ public class MatrixVariablesMapMethodArgumentResolverTests { @Test public void resolveArgument() throws Exception { - MultiValueMap params = getMatrixVariables("cars"); params.add("colors", "red"); params.add("colors", "green"); @@ -113,7 +113,6 @@ public class MatrixVariablesMapMethodArgumentResolverTests { @Test public void resolveArgumentPathVariable() throws Exception { - MultiValueMap params1 = getMatrixVariables("cars"); params1.add("colors", "red"); params1.add("colors", "purple"); @@ -137,7 +136,6 @@ public class MatrixVariablesMapMethodArgumentResolverTests { @Test public void resolveArgumentNoParams() throws Exception { - @SuppressWarnings("unchecked") Map map = (Map) this.resolver.resolveArgument( this.paramMap, this.mavContainer, this.webRequest, null); @@ -147,7 +145,6 @@ public class MatrixVariablesMapMethodArgumentResolverTests { @Test public void resolveArgumentNoMatch() throws Exception { - MultiValueMap params2 = getMatrixVariables("planes"); params2.add("colors", "yellow"); params2.add("colors", "orange"); @@ -162,7 +159,6 @@ public class MatrixVariablesMapMethodArgumentResolverTests { @SuppressWarnings("unchecked") private MultiValueMap getMatrixVariables(String pathVarName) { - Map> matrixVariables = (Map>) this.request.getAttribute( HandlerMapping.MATRIX_VARIABLES_ATTRIBUTE); @@ -182,4 +178,4 @@ public class MatrixVariablesMapMethodArgumentResolverTests { @MatrixVariable("name") Map mapWithName) { } -} \ No newline at end of file +} diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestPartMethodArgumentResolverTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestPartMethodArgumentResolverTests.java index d3a04537dd..5b443ff7fd 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestPartMethodArgumentResolverTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestPartMethodArgumentResolverTests.java @@ -16,16 +16,12 @@ package org.springframework.web.servlet.mvc.method.annotation; -import static org.junit.Assert.*; -import static org.mockito.BDDMockito.*; - import java.lang.reflect.Method; import java.nio.charset.Charset; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Optional; - import javax.servlet.http.Part; import javax.validation.Valid; import javax.validation.constraints.NotNull; @@ -36,6 +32,7 @@ import org.junit.Test; import org.springframework.core.LocalVariableTableParameterNameDiscoverer; import org.springframework.core.MethodParameter; +import org.springframework.core.annotation.SynthesizingMethodParameter; import org.springframework.http.HttpInputMessage; import org.springframework.http.MediaType; import org.springframework.http.converter.HttpMessageConverter; @@ -58,6 +55,9 @@ import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.support.MissingServletRequestPartException; import org.springframework.web.multipart.support.RequestPartServletServerHttpRequest; +import static org.junit.Assert.*; +import static org.mockito.BDDMockito.*; + /** * Test fixture with {@link RequestPartMethodArgumentResolver} and mock {@link HttpMessageConverter}. * @@ -102,26 +102,26 @@ public class RequestPartMethodArgumentResolverTests { Integer.TYPE, MultipartFile.class, Part.class, List.class, Part[].class, MultipartFile.class, Optional.class, Optional.class, Optional.class); - paramRequestPart = new MethodParameter(method, 0); + paramRequestPart = new SynthesizingMethodParameter(method, 0); paramRequestPart.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer()); - paramNamedRequestPart = new MethodParameter(method, 1); - paramValidRequestPart = new MethodParameter(method, 2); - paramMultipartFile = new MethodParameter(method, 3); - paramMultipartFileList = new MethodParameter(method, 4); - paramMultipartFileArray = new MethodParameter(method, 5); - paramInt = new MethodParameter(method, 6); - paramMultipartFileNotAnnot = new MethodParameter(method, 7); + paramNamedRequestPart = new SynthesizingMethodParameter(method, 1); + paramValidRequestPart = new SynthesizingMethodParameter(method, 2); + paramMultipartFile = new SynthesizingMethodParameter(method, 3); + paramMultipartFileList = new SynthesizingMethodParameter(method, 4); + paramMultipartFileArray = new SynthesizingMethodParameter(method, 5); + paramInt = new SynthesizingMethodParameter(method, 6); + paramMultipartFileNotAnnot = new SynthesizingMethodParameter(method, 7); paramMultipartFileNotAnnot.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer()); - paramPart = new MethodParameter(method, 8); + paramPart = new SynthesizingMethodParameter(method, 8); paramPart.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer()); - paramPartList = new MethodParameter(method, 9); - paramPartArray = new MethodParameter(method, 10); - paramRequestParamAnnot = new MethodParameter(method, 11); - optionalMultipartFile = new MethodParameter(method, 12); + paramPartList = new SynthesizingMethodParameter(method, 9); + paramPartArray = new SynthesizingMethodParameter(method, 10); + paramRequestParamAnnot = new SynthesizingMethodParameter(method, 11); + optionalMultipartFile = new SynthesizingMethodParameter(method, 12); optionalMultipartFile.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer()); - optionalPart = new MethodParameter(method, 13); + optionalPart = new SynthesizingMethodParameter(method, 13); optionalPart.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer()); - optionalRequestPart = new MethodParameter(method, 14); + optionalRequestPart = new SynthesizingMethodParameter(method, 14); messageConverter = mock(HttpMessageConverter.class); given(messageConverter.getSupportedMediaTypes()).willReturn(Collections.singletonList(MediaType.TEXT_PLAIN)); diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletCookieValueMethodArgumentResolverTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletCookieValueMethodArgumentResolverTests.java index cd18d1e959..5796f1248f 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletCookieValueMethodArgumentResolverTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletCookieValueMethodArgumentResolverTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2015 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. @@ -23,6 +23,7 @@ import org.junit.Before; import org.junit.Test; import org.springframework.core.MethodParameter; +import org.springframework.core.annotation.SynthesizingMethodParameter; import org.springframework.mock.web.test.MockHttpServletRequest; import org.springframework.mock.web.test.MockHttpServletResponse; import org.springframework.web.bind.annotation.CookieValue; @@ -48,18 +49,20 @@ public class ServletCookieValueMethodArgumentResolverTests { private MockHttpServletRequest request; + @Before public void setUp() throws Exception { resolver = new ServletCookieValueMethodArgumentResolver(null); Method method = getClass().getMethod("params", Cookie.class, String.class); - cookieParameter = new MethodParameter(method, 0); - cookieStringParameter = new MethodParameter(method, 1); + cookieParameter = new SynthesizingMethodParameter(method, 0); + cookieStringParameter = new SynthesizingMethodParameter(method, 1); request = new MockHttpServletRequest(); webRequest = new ServletWebRequest(request, new MockHttpServletResponse()); } + @Test public void resolveCookieArgument() throws Exception { Cookie expected = new Cookie("name", "foo"); @@ -78,8 +81,9 @@ public class ServletCookieValueMethodArgumentResolverTests { assertEquals("Invalid result", cookie.getValue(), result); } + public void params(@CookieValue("name") Cookie cookie, @CookieValue(name = "name", defaultValue = "bar") String cookieString) { } -} \ No newline at end of file +}