Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: rstoyanchev/spring-framework
...
head fork: rstoyanchev/spring-framework
  • 11 commits
  • 23 files changed
  • 0 commit comments
  • 2 contributors
Commits on Apr 02, 2012
@rstoyanchev Improvement in AntPathMatcher.combine method
Issues: SPR-7970
9833a4c
@rstoyanchev Fix bug with custom RequestCondition
A custom RequestCondition which can be provided by overriding methods
in RequestMappingHandlerMapping worked only for conditions that match
and did not return null (as it should have) for conditions that don't
match.

Issues: SPR-9134
64ee5e5
@rstoyanchev Fix race condition in AnntationMethodHER
Issues: SPR-9138
0b02933
@rstoyanchev Fix issue with parsing media types
Invalid Content-Type or Accept header values previously resulted in the
IllegalArgumentException getting propagated. After this change such
errors are detected and generally treated as a "no match", which
may for example result in a 406 in the case of the Accept header.

Issue: SPR-9148
ca8b98e
@rstoyanchev Make 'Content-Disposition' header case insensitive
Previously 'Content-Disposition' was passed to Part.getHeader(String).
However the Javadoc for that method specifies the header should be
case insensitive. Note that the JavaDoc in tomcat-servlet-api doesn't
mention this. It can only be found in the official api JavaDoc:

http://download.oracle.com/otndocs/jcp/servlet-3.0-fr-oth-JSpec/

Issue: SPR-9149
a17a889
Commits on Apr 06, 2012
@rstoyanchev Minor improvement in ExceptionHandlerExceptionResolver
Moved a null check inside a protected method to give protected method
a chance to override what happens in that case.

Issues: SPR-9193
97c22fc
@rstoyanchev Use the type of the actual return value in @MVC
The new @MVC support classes select a HandlerMethodArgumentResolver
and a HandlerMethodReturnValueHandler statically, i.e. based on
the signature of the method, which means that a controller method
can't declare a more general return type like Object but actually
return a more specific one, e.g.  String vs RedirectView, and
expect the right handler to be used.

The fix ensures that a HandlerMethodReturnValueHandler is selected
based on the actual return value type, which is something that was
supported with the old @MVC support classes. One consequence
of the change is the selected HandlerMethodReturnValueHandler can
no longer be cached but that matches the behavior of the old
@MVC support classes.

Issues: SPR-9218
cfe2af7
Commits on Apr 13, 2012
@cbeams cbeams Fix typo in reference documentation
Issue: SPR-9321
f6003b5
Commits on Apr 14, 2012
@cbeams cbeams Upgrade to Gradle 1.0-rc1
 - Fix deprecation warnings about dynamic properties; favor use of
   "extra properties extensions" per [1]

 - Certain such deprecations are still issued due to violations within
   the docbook-reference plugin. These will be fixed in an upcoming
   revision of the plugin, at which point spring-framework will upgrade
   to depend on it and these warnings will be eliminated

[1] http://gradle.org/docs/current/dsl/org.gradle.api.plugins.ExtraPropertiesExtension.html

Issue: SPR-9327
963b4e4
@cbeams cbeams Upgrade AspectJ from 1.6.8 to 1.6.12
 - Spring remains compatible against AJ version 1.6.8, but is now
   compiling and testing against 1.6.12

 - Encountered what appears to be an AJ bug introduced in 1.6.10: an
   assertion in org.aspectj.weaver.UnresolvedType causes a false
   negative failure when encountering org.springframework.io.Resource
   arrays, e.g. "[org.springframework.io.Resource@xxx". This problem
   has been reported to the AJ team and in the meantime, the recommended
   workaround is to disable assertions either completely, or at least
   selectively with

       -disableassertions:org.aspectj.weaver.UnresolvedType

Issue: SPR-7989, SPR-9272
0ab9e9a
Commits on Apr 16, 2012
@cbeams cbeams Fix typo in ApplicationContext reference doc 57b89e0
Showing with 349 additions and 225 deletions.
  1. +12 −7 build.gradle
  2. +2 −2 gradle/wrapper/gradle-wrapper.properties
  3. +4 −4 publish-maven.gradle
  4. +3 −1 spring-core/src/main/java/org/springframework/util/AntPathMatcher.java
  5. +8 −7 spring-core/src/test/java/org/springframework/util/AntPathMatcherTests.java
  6. +10 −10 spring-oxm/oxm.gradle
  7. +44 −29 spring-web/src/main/java/org/springframework/web/method/HandlerMethod.java
  8. +8 −18 spring-web/src/main/java/org/springframework/web/method/support/HandlerMethodReturnValueHandlerComposite.java
  9. +2 −2 spring-web/src/main/java/org/springframework/web/multipart/support/StandardMultipartHttpServletRequest.java
  10. +17 −17 .../src/main/java/org/springframework/web/portlet/mvc/annotation/AnnotationMethodHandlerExceptionResolver.java
  11. +18 −18 .../src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerExceptionResolver.java
  12. +16 −4 spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/AbstractMediaTypeExpression.java
  13. +13 −13 spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/RequestConditionHolder.java
  14. +17 −9 ...ain/java/org/springframework/web/servlet/mvc/method/annotation/AbstractMessageConverterMethodProcessor.java
  15. +30 −32 .../src/main/java/org/springframework/web/servlet/mvc/method/annotation/ExceptionHandlerExceptionResolver.java
  16. +1 −1  ...bmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletInvocableHandlerMethod.java
  17. +24 −4 spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/condition/ConsumesRequestConditionTests.java
  18. +29 −9 spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/condition/ProducesRequestConditionTests.java
  19. +19 −12 spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/condition/RequestConditionHolderTests.java
  20. +16 −5 ...mvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/HttpEntityMethodProcessorTests.java
  21. +45 −19 ...src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletInvocableHandlerMethodTests.java
  22. +9 −0 src/dist/changelog.txt
  23. +2 −2 src/reference/docbook/beans.xml
View
19 build.gradle
@@ -17,7 +17,8 @@ configure(allprojects) {
sourceCompatibility=1.5
targetCompatibility=1.5
- slf4jLog4jVersion = '1.5.10'
+ ext.slf4jLog4jVersion = '1.5.10'
+ ext.aspectjVersion = '1.6.12'
[compileJava, compileTestJava]*.options*.compilerArgs = ['-Xlint:none']
@@ -85,7 +86,7 @@ configure(subprojects) { subproject ->
project("spring-asm") {
description = 'Spring ASM'
- asmVersion = '2.2.3'
+ ext.asmVersion = '2.2.3'
configurations {
asm
@@ -133,7 +134,7 @@ project('spring-core') {
builtBy project(":spring-asm").jar
}
compile "commons-logging:commons-logging:1.1.1"
- compile("org.aspectj:aspectjweaver:1.6.8", optional)
+ compile("org.aspectj:aspectjweaver:${aspectjVersion}", optional)
compile("net.sf.jopt-simple:jopt-simple:3.0") { dep ->
optional dep
exclude group: 'org.apache.ant', module: 'ant'
@@ -220,6 +221,10 @@ project('spring-context') {
testCompile("javax.xml:jaxrpc-api:1.1")
testCompile("javax.inject:com.springsource.org.atinject.tck:1.0.0")
}
+
+ test {
+ jvmArgs = ['-disableassertions:org.aspectj.weaver.UnresolvedType'] // SPR-7989
+ }
}
project('spring-tx') {
@@ -439,8 +444,8 @@ project('spring-aspects') {
dependencies {
compile project(":spring-orm")
aspects project(":spring-orm")
- ajc "org.aspectj:aspectjtools:1.6.8"
- compile "org.aspectj:aspectjrt:1.6.8"
+ ajc "org.aspectj:aspectjtools:${aspectjVersion}"
+ compile "org.aspectj:aspectjrt:${aspectjVersion}"
testCompile project(":spring-test")
}
eclipse.project {
@@ -542,7 +547,7 @@ configure(rootProject) {
description = "Builds -${classifier} archive, containing all jars and docs, " +
"suitable for community download page."
- baseDir = "${project.name}-${project.version}";
+ def baseDir = "${project.name}-${project.version}";
from('src/dist') {
include 'readme.txt'
@@ -581,7 +586,7 @@ configure(rootProject) {
task wrapper(type: Wrapper) {
description = 'Generates gradlew[.bat] scripts'
- gradleVersion = '1.0-milestone-8a'
+ gradleVersion = '1.0-rc-1'
}
}
View
4 gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Thu Feb 23 13:43:17 CET 2012
+#Sat Apr 14 10:56:11 EEST 2012
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=http\://services.gradle.org/distributions/gradle-1.0-milestone-8a-bin.zip
+distributionUrl=http\://services.gradle.org/distributions/gradle-1.0-rc-1-bin.zip
View
8 publish-maven.gradle
@@ -1,10 +1,10 @@
apply plugin: 'maven'
-optionalDeps = []
-providedDeps = []
+ext.optionalDeps = []
+ext.providedDeps = []
-optional = { optionalDeps << it }
-provided = { providedDeps << it }
+ext.optional = { optionalDeps << it }
+ext.provided = { providedDeps << it }
install {
repositories.mavenInstaller {
View
4 spring-core/src/main/java/org/springframework/util/AntPathMatcher.java
@@ -299,7 +299,9 @@ else if (!StringUtils.hasText(pattern1)) {
else if (!StringUtils.hasText(pattern2)) {
return pattern1;
}
- else if (!pattern1.contains("{") && match(pattern1, pattern2)) {
+ else if (!pattern1.equals(pattern2) && !pattern1.contains("{") && match(pattern1, pattern2)) {
+ // /* + /hotel -> /hotel ; "/*.*" + "/*.html" -> /*.html
+ // However /user + /user -> /usr/user ; /{foo} + /bar -> /{foo}/bar
return pattern2;
}
else if (pattern1.endsWith("/*")) {
View
15 spring-core/src/test/java/org/springframework/util/AntPathMatcherTests.java
@@ -348,13 +348,13 @@ public void extractUriTemplateVariablesRegex() {
assertEquals("com.example", result.get("symbolicName"));
assertEquals("1.0.0", result.get("version"));
}
-
+
// SPR-7787
-
+
@Test
public void extractUriTemplateVarsRegexQualifiers() {
Map<String, String> result = pathMatcher.extractUriTemplateVariables(
- "{symbolicName:[\\p{L}\\.]+}-sources-{version:[\\p{N}\\.]+}.jar",
+ "{symbolicName:[\\p{L}\\.]+}-sources-{version:[\\p{N}\\.]+}.jar",
"com.example-sources-1.0.0.jar");
assertEquals("com.example", result.get("symbolicName"));
assertEquals("1.0.0", result.get("version"));
@@ -376,18 +376,18 @@ public void extractUriTemplateVarsRegexQualifiers() {
}
// SPR-8455
-
+
@Test
public void extractUriTemplateVarsRegexCapturingGroups() {
try {
pathMatcher.extractUriTemplateVariables("/web/{id:foo(bar)?}", "/web/foobar");
fail("Expected exception");
} catch (IllegalArgumentException e) {
- assertTrue("Expected helpful message on the use of capturing groups",
+ assertTrue("Expected helpful message on the use of capturing groups",
e.getMessage().contains("The number of capturing groups in the pattern"));
}
}
-
+
@Test
public void combine() {
assertEquals("", pathMatcher.combine(null, null));
@@ -410,7 +410,8 @@ public void combine() {
assertEquals("/*.html", pathMatcher.combine("/**", "/*.html"));
assertEquals("/*.html", pathMatcher.combine("/*", "/*.html"));
assertEquals("/*.html", pathMatcher.combine("/*.*", "/*.html"));
- assertEquals("/{foo}/bar", pathMatcher.combine("/{foo}", "/bar"));
+ assertEquals("/{foo}/bar", pathMatcher.combine("/{foo}", "/bar")); // SPR-8858
+ assertEquals("/user/user", pathMatcher.combine("/user", "/user")); // SPR-7970
}
@Test
View
20 spring-oxm/oxm.gradle
@@ -13,15 +13,15 @@ dependencies {
jibx "bcel:bcel:5.1"
}
-genSourcesDir = "${buildDir}/generated-sources"
-flightSchema = "${projectDir}/src/test/resources/org/springframework/oxm/flight.xsd"
+ext.genSourcesDir = "${buildDir}/generated-sources"
+ext.flightSchema = "${projectDir}/src/test/resources/org/springframework/oxm/flight.xsd"
task genCastor {
- orderSchema = "${projectDir}/src/test/resources/org/springframework/oxm/order.xsd"
- castorBuilderProperties = "${projectDir}/src/test/castor/castorbuilder.properties"
+ def orderSchema = "${projectDir}/src/test/resources/org/springframework/oxm/order.xsd"
+ def castorBuilderProperties = "${projectDir}/src/test/castor/castorbuilder.properties"
- sourcesDir = "${genSourcesDir}/castor"
- classesDir = "${buildDir}/classes/castor"
+ ext.sourcesDir = "${genSourcesDir}/castor"
+ ext.classesDir = "${buildDir}/classes/castor"
inputs.files flightSchema, orderSchema, castorBuilderProperties
outputs.dir classesDir
@@ -56,8 +56,8 @@ task genCastor {
}
task genJaxb {
- sourcesDir = "${genSourcesDir}/jaxb"
- classesDir = "${buildDir}/classes/jaxb"
+ ext.sourcesDir = "${genSourcesDir}/jaxb"
+ ext.classesDir = "${buildDir}/classes/jaxb"
inputs.files flightSchema
outputs.dir classesDir
@@ -92,7 +92,7 @@ task genJaxb {
}
task genXmlbeans {
- classesDir = "${buildDir}/classes/xmlbeans"
+ ext.classesDir = "${buildDir}/classes/xmlbeans"
inputs.files flightSchema
outputs.dir classesDir
@@ -112,7 +112,7 @@ task genXmlbeans {
// add jibx binding to the normal test compilation process
compileTestJava {
- bindingXml = "${projectDir}/src/test/resources/org/springframework/oxm/jibx/binding.xml"
+ def bindingXml = "${projectDir}/src/test/resources/org/springframework/oxm/jibx/binding.xml"
doLast() {
project.ant {
View
73 spring-web/src/main/java/org/springframework/web/method/HandlerMethod.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2011 the original author or authors.
+ * Copyright 2002-2012 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.
@@ -29,13 +29,13 @@
import org.springframework.util.ClassUtils;
/**
- * Encapsulates information about a bean method consisting of a {@linkplain #getMethod() method} and a
- * {@linkplain #getBean() bean}. Provides convenient access to method parameters, the method return value,
+ * Encapsulates information about a bean method consisting of a {@linkplain #getMethod() method} and a
+ * {@linkplain #getBean() bean}. Provides convenient access to method parameters, the method return value,
* method annotations.
*
* <p>The class may be created with a bean instance or with a bean name (e.g. lazy bean, prototype bean).
* Use {@link #createWithResolvedBean()} to obtain an {@link HandlerMethod} instance with a bean instance
- * initialized through the bean factory.
+ * initialized through the bean factory.
*
* @author Arjen Poutsma
* @author Rossen Stoyanchev
@@ -49,7 +49,7 @@
private final Object bean;
private final Method method;
-
+
private final BeanFactory beanFactory;
private MethodParameter[] parameters;
@@ -87,7 +87,7 @@ public HandlerMethod(Object bean, String methodName, Class<?>... parameterTypes)
}
/**
- * Constructs a new handler method with the given bean name and method. The bean name will be lazily
+ * Constructs a new handler method with the given bean name and method. The bean name will be lazily
* initialized when {@link #createWithResolvedBean()} is called.
* @param beanName the bean name
* @param beanFactory the bean factory to use for bean initialization
@@ -120,7 +120,7 @@ public Method getMethod() {
}
/**
- * Returns the type of the handler for this handler method.
+ * Returns the type of the handler for this handler method.
* Note that if the bean type is a CGLIB-generated class, the original, user-defined class is returned.
*/
public Class<?> getBeanType() {
@@ -132,7 +132,7 @@ public Method getMethod() {
return ClassUtils.getUserClass(bean.getClass());
}
}
-
+
/**
* If the bean method is a bridge method, this method returns the bridged (user-defined) method.
* Otherwise it returns the same method as {@link #getMethod()}.
@@ -149,7 +149,7 @@ protected Method getBridgedMethod() {
int parameterCount = this.bridgedMethod.getParameterTypes().length;
MethodParameter[] p = new MethodParameter[parameterCount];
for (int i = 0; i < parameterCount; i++) {
- p[i] = new HandlerMethodParameter(this.bridgedMethod, i);
+ p[i] = new HandlerMethodParameter(i);
}
this.parameters = p;
}
@@ -157,10 +157,17 @@ protected Method getBridgedMethod() {
}
/**
- * Returns the method return type, as {@code MethodParameter}.
+ * Return the HandlerMethod return type.
*/
public MethodParameter getReturnType() {
- return new HandlerMethodParameter(this.bridgedMethod, -1);
+ return new HandlerMethodParameter(-1);
+ }
+
+ /**
+ * Return the actual return value type.
+ */
+ public MethodParameter getReturnValueType(Object returnValue) {
+ return new ReturnValueMethodParameter(returnValue);
}
/**
@@ -171,8 +178,8 @@ public boolean isVoid() {
}
/**
- * Returns a single annotation on the underlying method traversing its super methods if no
- * annotation can be found on the given method itself.
+ * Returns a single annotation on the underlying method traversing its super methods if no
+ * annotation can be found on the given method itself.
* @param annotationType the type of annotation to introspect the method for.
* @return the annotation, or {@code null} if none found
*/
@@ -181,7 +188,7 @@ public boolean isVoid() {
}
/**
- * If the provided instance contains a bean name rather than an object instance, the bean name is resolved
+ * If the provided instance contains a bean name rather than an object instance, the bean name is resolved
* before a {@link HandlerMethod} is created and returned.
*/
public HandlerMethod createWithResolvedBean() {
@@ -192,7 +199,7 @@ public HandlerMethod createWithResolvedBean() {
}
return new HandlerMethod(handler, method);
}
-
+
@Override
public boolean equals(Object o) {
if (this == o) {
@@ -216,33 +223,41 @@ public String toString() {
}
/**
- * A {@link MethodParameter} that resolves method annotations even when the actual annotations
- * are on a bridge method rather than on the current method. Annotations on super types are
- * also returned via {@link AnnotationUtils#findAnnotation(Method, Class)}.
+ * A MethodParameter with HandlerMethod-specific behavior.
*/
private class HandlerMethodParameter extends MethodParameter {
-
- public HandlerMethodParameter(Method method, int parameterIndex) {
- super(method, parameterIndex);
+
+ protected HandlerMethodParameter(int index) {
+ super(HandlerMethod.this.bridgedMethod, index);
}
- /**
- * Return {@link HandlerMethod#getBeanType()} rather than the method's class, which could be
- * important for the proper discovery of generic types.
- */
@Override
public Class<?> getDeclaringClass() {
return HandlerMethod.this.getBeanType();
}
- /**
- * Return the method annotation via {@link HandlerMethod#getMethodAnnotation(Class)}, which will find
- * the annotation by traversing super-types and handling annotations on bridge methods correctly.
- */
@Override
public <T extends Annotation> T getMethodAnnotation(Class<T> annotationType) {
return HandlerMethod.this.getMethodAnnotation(annotationType);
}
}
+ /**
+ * A MethodParameter for a HandlerMethod return type based on an actual return value.
+ */
+ private class ReturnValueMethodParameter extends HandlerMethodParameter {
+
+ private final Object returnValue;
+
+ public ReturnValueMethodParameter(Object returnValue) {
+ super(-1);
+ this.returnValue = returnValue;
+ }
+
+ @Override
+ public Class<?> getParameterType() {
+ return (this.returnValue != null) ? this.returnValue.getClass() : super.getParameterType();
+ }
+ }
+
}
View
26 ...java/org/springframework/web/method/support/HandlerMethodReturnValueHandlerComposite.java
@@ -19,8 +19,6 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -42,9 +40,6 @@
private final List<HandlerMethodReturnValueHandler> returnValueHandlers =
new ArrayList<HandlerMethodReturnValueHandler>();
- private final Map<MethodParameter, HandlerMethodReturnValueHandler> returnValueHandlerCache =
- new ConcurrentHashMap<MethodParameter, HandlerMethodReturnValueHandler>();
-
/**
* Return a read-only list with the registered handlers, or an empty list.
*/
@@ -78,21 +73,16 @@ public void handleReturnValue(
* Find a registered {@link HandlerMethodReturnValueHandler} that supports the given return type.
*/
private HandlerMethodReturnValueHandler getReturnValueHandler(MethodParameter returnType) {
- HandlerMethodReturnValueHandler result = this.returnValueHandlerCache.get(returnType);
- if (result == null) {
- for (HandlerMethodReturnValueHandler returnValueHandler : returnValueHandlers) {
- if (logger.isTraceEnabled()) {
- logger.trace("Testing if return value handler [" + returnValueHandler + "] supports [" +
- returnType.getGenericParameterType() + "]");
- }
- if (returnValueHandler.supportsReturnType(returnType)) {
- result = returnValueHandler;
- this.returnValueHandlerCache.put(returnType, returnValueHandler);
- break;
- }
+ for (HandlerMethodReturnValueHandler returnValueHandler : returnValueHandlers) {
+ if (logger.isTraceEnabled()) {
+ logger.trace("Testing if return value handler [" + returnValueHandler + "] supports [" +
+ returnType.getGenericParameterType() + "]");
+ }
+ if (returnValueHandler.supportsReturnType(returnType)) {
+ return returnValueHandler;
}
}
- return result;
+ return null;
}
/**
View
4 ...n/java/org/springframework/web/multipart/support/StandardMultipartHttpServletRequest.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2011 the original author or authors.
+ * Copyright 2002-2012 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.
@@ -41,7 +41,7 @@
*/
public class StandardMultipartHttpServletRequest extends AbstractMultipartHttpServletRequest {
- private static final String CONTENT_DISPOSITION = "Content-Disposition";
+ private static final String CONTENT_DISPOSITION = "content-disposition";
private static final String FILENAME_KEY = "filename=";
View
34 .../springframework/web/portlet/mvc/annotation/AnnotationMethodHandlerExceptionResolver.java
@@ -75,8 +75,7 @@
public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExceptionResolver {
// dummy method placeholder
- private static final Method NO_METHOD_FOUND = ClassUtils
- .getMethodIfAvailable(System.class, "currentTimeMillis", null);
+ private static final Method NO_METHOD_FOUND = ClassUtils.getMethodIfAvailable(System.class, "currentTimeMillis", (Class<?>[]) null);
private WebArgumentResolver[] customArgumentResolvers;
@@ -134,10 +133,9 @@ protected ModelAndView doResolveException(
private Method findBestExceptionHandlerMethod(Object handler, final Exception thrownException) {
final Class<?> handlerType = handler.getClass();
final Class<? extends Throwable> thrownExceptionType = thrownException.getClass();
-
Method handlerMethod = null;
- Map<Class<? extends Throwable>, Method> handlers = exceptionHandlerCache
- .get(handlerType);
+
+ Map<Class<? extends Throwable>, Method> handlers = exceptionHandlerCache.get(handlerType);
if (handlers != null) {
handlerMethod = handlers.get(thrownExceptionType);
@@ -173,7 +171,9 @@ public void doWith(Method method) {
}
});
- return getBestMatchingMethod(resolverMethods, thrownException);
+ handlerMethod = getBestMatchingMethod(resolverMethods, thrownException);
+ handlers.put(thrownExceptionType, (handlerMethod == null ? NO_METHOD_FOUND : handlerMethod));
+ return handlerMethod;
}
/**
@@ -204,19 +204,19 @@ public void doWith(Method method) {
}
/**
- * Returns the best matching method. Uses the {@link DepthComparator}.
+ * Uses the {@link DepthComparator} to find the best matching method
+ * @return the best matching method or {@code null}.
*/
private Method getBestMatchingMethod(
Map<Class<? extends Throwable>, Method> resolverMethods, Exception thrownException) {
- if (!resolverMethods.isEmpty()) {
- Class<? extends Throwable> closestMatch =
- ExceptionDepthComparator.findClosestMatch(resolverMethods.keySet(), thrownException);
- return resolverMethods.get(closestMatch);
- }
- else {
+ if (resolverMethods.isEmpty()) {
return null;
}
+ Class<? extends Throwable> closestMatch =
+ ExceptionDepthComparator.findClosestMatch(resolverMethods.keySet(), thrownException);
+ Method method = resolverMethods.get(closestMatch);
+ return ((method == null) || (NO_METHOD_FOUND == method)) ? null : method;
}
/**
@@ -225,13 +225,13 @@ private Method getBestMatchingMethod(
private Object[] resolveHandlerArguments(Method handlerMethod, Object handler,
NativeWebRequest webRequest, Exception thrownException) throws Exception {
- Class[] paramTypes = handlerMethod.getParameterTypes();
+ Class<?>[] paramTypes = handlerMethod.getParameterTypes();
Object[] args = new Object[paramTypes.length];
Class<?> handlerType = handler.getClass();
for (int i = 0; i < args.length; i++) {
MethodParameter methodParam = new MethodParameter(handlerMethod, i);
GenericTypeResolver.resolveParameterType(methodParam, handlerType);
- Class paramType = methodParam.getParameterType();
+ Class<?> paramType = methodParam.getParameterType();
Object argValue = resolveCommonArgument(methodParam, webRequest, thrownException);
if (argValue != WebArgumentResolver.UNRESOLVED) {
args[i] = argValue;
@@ -267,7 +267,7 @@ protected Object resolveCommonArgument(MethodParameter methodParameter, NativeWe
}
// Resolution of standard parameter types...
- Class paramType = methodParameter.getParameterType();
+ Class<?> paramType = methodParameter.getParameterType();
Object value = resolveStandardArgument(paramType, webRequest, thrownException);
if (value != WebArgumentResolver.UNRESOLVED && !ClassUtils.isAssignableValue(paramType, value)) {
throw new IllegalStateException("Standard argument type [" + paramType.getName() +
@@ -287,7 +287,7 @@ protected Object resolveCommonArgument(MethodParameter methodParameter, NativeWe
* @param thrownException the exception thrown
* @return the argument value, or {@link org.springframework.web.bind.support.WebArgumentResolver#UNRESOLVED}
*/
- protected Object resolveStandardArgument(Class parameterType, NativeWebRequest webRequest,
+ protected Object resolveStandardArgument(Class<?> parameterType, NativeWebRequest webRequest,
Exception thrownException) throws Exception {
if (parameterType.isInstance(thrownException)) {
View
36 .../springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerExceptionResolver.java
@@ -84,10 +84,10 @@
public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExceptionResolver {
// dummy method placeholder
- private static final Method NO_METHOD_FOUND = ClassUtils.getMethodIfAvailable(System.class, "currentTimeMillis", null);
-
- private final Map<Class<?>, Map<Class<? extends Throwable>, Method>> exceptionHandlerCache =
- new ConcurrentHashMap<Class<?>, Map<Class<? extends Throwable>, Method>>();
+ private static final Method NO_METHOD_FOUND = ClassUtils.getMethodIfAvailable(System.class, "currentTimeMillis", (Class<?>[]) null);
+
+ private final Map<Class<?>, Map<Class<? extends Throwable>, Method>> exceptionHandlerCache =
+ new ConcurrentHashMap<Class<?>, Map<Class<? extends Throwable>, Method>>();
private WebArgumentResolver[] customArgumentResolvers;
@@ -157,7 +157,7 @@ private Method findBestExceptionHandlerMethod(Object handler, final Exception th
final Class<?> handlerType = ClassUtils.getUserClass(handler);
final Class<? extends Throwable> thrownExceptionType = thrownException.getClass();
Method handlerMethod = null;
-
+
Map<Class<? extends Throwable>, Method> handlers = exceptionHandlerCache.get(handlerType);
if (handlers != null) {
@@ -170,7 +170,7 @@ private Method findBestExceptionHandlerMethod(Object handler, final Exception th
handlers = new ConcurrentHashMap<Class<? extends Throwable>, Method>();
exceptionHandlerCache.put(handlerType, handlers);
}
-
+
final Map<Class<? extends Throwable>, Method> resolverMethods = handlers;
ReflectionUtils.doWithMethods(handlerType, new ReflectionUtils.MethodCallback() {
@@ -228,19 +228,19 @@ public void doWith(Method method) {
}
/**
- * Returns the best matching method. Uses the {@link DepthComparator}.
+ * Uses the {@link DepthComparator} to find the best matching method
+ * @return the best matching method or {@code null}.
*/
private Method getBestMatchingMethod(
Map<Class<? extends Throwable>, Method> resolverMethods, Exception thrownException) {
- if (!resolverMethods.isEmpty()) {
- Class<? extends Throwable> closestMatch =
- ExceptionDepthComparator.findClosestMatch(resolverMethods.keySet(), thrownException);
- return resolverMethods.get(closestMatch);
- }
- else {
+ if (resolverMethods.isEmpty()) {
return null;
}
+ Class<? extends Throwable> closestMatch =
+ ExceptionDepthComparator.findClosestMatch(resolverMethods.keySet(), thrownException);
+ Method method = resolverMethods.get(closestMatch);
+ return ((method == null) || (NO_METHOD_FOUND == method)) ? null : method;
}
/**
@@ -249,13 +249,13 @@ private Method getBestMatchingMethod(
private Object[] resolveHandlerArguments(Method handlerMethod, Object handler,
NativeWebRequest webRequest, Exception thrownException) throws Exception {
- Class[] paramTypes = handlerMethod.getParameterTypes();
+ Class<?>[] paramTypes = handlerMethod.getParameterTypes();
Object[] args = new Object[paramTypes.length];
Class<?> handlerType = handler.getClass();
for (int i = 0; i < args.length; i++) {
MethodParameter methodParam = new MethodParameter(handlerMethod, i);
GenericTypeResolver.resolveParameterType(methodParam, handlerType);
- Class paramType = methodParam.getParameterType();
+ Class<?> paramType = methodParam.getParameterType();
Object argValue = resolveCommonArgument(methodParam, webRequest, thrownException);
if (argValue != WebArgumentResolver.UNRESOLVED) {
args[i] = argValue;
@@ -290,7 +290,7 @@ protected Object resolveCommonArgument(MethodParameter methodParameter, NativeWe
}
// Resolution of standard parameter types...
- Class paramType = methodParameter.getParameterType();
+ Class<?> paramType = methodParameter.getParameterType();
Object value = resolveStandardArgument(paramType, webRequest, thrownException);
if (value != WebArgumentResolver.UNRESOLVED && !ClassUtils.isAssignableValue(paramType, value)) {
throw new IllegalStateException(
@@ -311,7 +311,7 @@ protected Object resolveCommonArgument(MethodParameter methodParameter, NativeWe
* @param thrownException the exception thrown
* @return the argument value, or {@link WebArgumentResolver#UNRESOLVED}
*/
- protected Object resolveStandardArgument(Class parameterType, NativeWebRequest webRequest,
+ protected Object resolveStandardArgument(Class<?> parameterType, NativeWebRequest webRequest,
Exception thrownException) throws Exception {
if (parameterType.isInstance(thrownException)) {
@@ -395,7 +395,7 @@ else if (returnValue instanceof Model) {
return new ModelAndView().addAllObjects(((Model) returnValue).asMap());
}
else if (returnValue instanceof Map) {
- return new ModelAndView().addAllObjects((Map) returnValue);
+ return new ModelAndView().addAllObjects((Map<String, Object>) returnValue);
}
else if (returnValue instanceof View) {
return new ModelAndView((View) returnValue);
View
20 .../main/java/org/springframework/web/servlet/mvc/condition/AbstractMediaTypeExpression.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2011 the original author or authors.
+ * Copyright 2002-2012 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.
@@ -18,19 +18,23 @@
import javax.servlet.http.HttpServletRequest;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* Supports media type expressions as described in:
* {@link RequestMapping#consumes()} and {@link RequestMapping#produces()}.
- *
+ *
* @author Arjen Poutsma
* @author Rossen Stoyanchev
* @since 3.1
*/
abstract class AbstractMediaTypeExpression implements Comparable<AbstractMediaTypeExpression>, MediaTypeExpression {
+ protected final Log logger = LogFactory.getLog(getClass());
+
private final MediaType mediaType;
private final boolean isNegated;
@@ -60,8 +64,16 @@ public boolean isNegated() {
}
public final boolean match(HttpServletRequest request) {
- boolean match = matchMediaType(request);
- return !isNegated ? match : !match;
+ try {
+ boolean match = matchMediaType(request);
+ return !isNegated ? match : !match;
+ }
+ catch (IllegalArgumentException ex) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Could not parse media type header: " + ex.getMessage());
+ }
+ return false;
+ }
}
protected abstract boolean matchMediaType(HttpServletRequest request);
View
26 ...c/src/main/java/org/springframework/web/servlet/mvc/condition/RequestConditionHolder.java
@@ -25,12 +25,12 @@
/**
* A holder for a {@link RequestCondition} useful when the type of the held
* request condition is not known ahead of time - e.g. custom condition.
- *
- * <p>An implementation of {@code RequestCondition} itself, a
- * {@code RequestConditionHolder} decorates the held request condition allowing
- * it to be combined and compared with other custom request conditions while
+ *
+ * <p>An implementation of {@code RequestCondition} itself, a
+ * {@code RequestConditionHolder} decorates the held request condition allowing
+ * it to be combined and compared with other custom request conditions while
* ensuring type and null safety.
- *
+ *
* @author Rossen Stoyanchev
* @since 3.1
*/
@@ -38,9 +38,9 @@
@SuppressWarnings("rawtypes")
private final RequestCondition condition;
-
+
/**
- * Create a new holder to wrap the given request condition.
+ * Create a new holder to wrap the given request condition.
* @param requestCondition the condition to hold, may be {@code null}
*/
public RequestConditionHolder(RequestCondition<?> requestCondition) {
@@ -65,7 +65,7 @@ protected String getToStringInfix() {
}
/**
- * Combine the request conditions held by the two RequestConditionHolder
+ * Combine the request conditions held by the two RequestConditionHolder
* instances after making sure the conditions are of the same type.
* Or if one holder is empty, the other holder is returned.
*/
@@ -97,9 +97,9 @@ private void assertIsCompatible(RequestConditionHolder other) {
throw new ClassCastException("Incompatible request conditions: " + clazz + " and " + otherClazz);
}
}
-
+
/**
- * Get the matching condition for the held request condition wrap it in a
+ * Get the matching condition for the held request condition wrap it in a
* new RequestConditionHolder instance. Or otherwise if this is an empty
* holder, return the same holder instance.
*/
@@ -108,11 +108,11 @@ public RequestConditionHolder getMatchingCondition(HttpServletRequest request) {
return this;
}
RequestCondition<?> match = (RequestCondition<?>) condition.getMatchingCondition(request);
- return new RequestConditionHolder(match);
+ return (match != null) ? new RequestConditionHolder(match) : null;
}
/**
- * Compare the request conditions held by the two RequestConditionHolder
+ * Compare the request conditions held by the two RequestConditionHolder
* instances after making sure the conditions are of the same type.
* Or if one holder is empty, the other holder is preferred.
*/
@@ -132,5 +132,5 @@ else if (other.condition == null) {
return condition.compareTo(other.condition, request);
}
}
-
+
}
View
26 ...gframework/web/servlet/mvc/method/annotation/AbstractMessageConverterMethodProcessor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2011 the original author or authors.
+ * Copyright 2002-2012 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.
@@ -41,7 +41,7 @@
import org.springframework.web.servlet.HandlerMapping;
/**
- * Extends {@link AbstractMessageConverterMethodArgumentResolver} with the ability to handle method return
+ * Extends {@link AbstractMessageConverterMethodArgumentResolver} with the ability to handle method return
* values by writing to the response with {@link HttpMessageConverter}s.
*
* @author Arjen Poutsma
@@ -103,7 +103,7 @@ protected ServletServerHttpResponse createOutputMessage(NativeWebRequest webRequ
List<MediaType> acceptableMediaTypes = getAcceptableMediaTypes(inputMessage);
List<MediaType> producibleMediaTypes = getProducibleMediaTypes(inputMessage.getServletRequest(), returnValueClass);
-
+
Set<MediaType> compatibleMediaTypes = new LinkedHashSet<MediaType>();
for (MediaType a : acceptableMediaTypes) {
for (MediaType p : producibleMediaTypes) {
@@ -115,10 +115,10 @@ protected ServletServerHttpResponse createOutputMessage(NativeWebRequest webRequ
if (compatibleMediaTypes.isEmpty()) {
throw new HttpMediaTypeNotAcceptableException(allSupportedMediaTypes);
}
-
+
List<MediaType> mediaTypes = new ArrayList<MediaType>(compatibleMediaTypes);
MediaType.sortBySpecificity(mediaTypes);
-
+
MediaType selectedMediaType = null;
for (MediaType mediaType : mediaTypes) {
if (mediaType.isConcrete()) {
@@ -130,7 +130,7 @@ else if (mediaType.equals(MediaType.ALL) || mediaType.equals(MEDIA_TYPE_APPLICAT
break;
}
}
-
+
if (selectedMediaType != null) {
for (HttpMessageConverter<?> messageConverter : messageConverters) {
if (messageConverter.canWrite(returnValueClass, selectedMediaType)) {
@@ -166,7 +166,7 @@ else if (!allSupportedMediaTypes.isEmpty()) {
if (converter.canWrite(returnValueClass, null)) {
result.addAll(converter.getSupportedMediaTypes());
}
- }
+ }
return result;
}
else {
@@ -175,8 +175,16 @@ else if (!allSupportedMediaTypes.isEmpty()) {
}
private List<MediaType> getAcceptableMediaTypes(HttpInputMessage inputMessage) {
- List<MediaType> result = inputMessage.getHeaders().getAccept();
- return result.isEmpty() ? Collections.singletonList(MediaType.ALL) : result;
+ try {
+ List<MediaType> result = inputMessage.getHeaders().getAccept();
+ return result.isEmpty() ? Collections.singletonList(MediaType.ALL) : result;
+ }
+ catch (IllegalArgumentException ex) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Could not parse Accept header: " + ex.getMessage());
+ }
+ return Collections.emptyList();
+ }
}
/**
View
62 .../springframework/web/servlet/mvc/method/annotation/ExceptionHandlerExceptionResolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2011 the original author or authors.
+ * Copyright 2002-2012 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,7 +56,7 @@
* {@link #setCustomArgumentResolvers} and {@link #setCustomReturnValueHandlers}.
* Or alternatively to re-configure all argument and return value types use
* {@link #setArgumentResolvers} and {@link #setReturnValueHandlers(List)}.
- *
+ *
* @author Rossen Stoyanchev
* @since 3.1
*/
@@ -73,17 +73,17 @@
new ConcurrentHashMap<Class<?>, ExceptionHandlerMethodResolver>();
private HandlerMethodArgumentResolverComposite argumentResolvers;
-
+
private HandlerMethodReturnValueHandlerComposite returnValueHandlers;
/**
* Default constructor.
*/
public ExceptionHandlerExceptionResolver() {
-
+
StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
stringHttpMessageConverter.setWriteAcceptCharset(false); // See SPR-7316
-
+
this.messageConverters = new ArrayList<HttpMessageConverter<?>>();
this.messageConverters.add(new ByteArrayHttpMessageConverter());
this.messageConverters.add(stringHttpMessageConverter);
@@ -93,13 +93,13 @@ public ExceptionHandlerExceptionResolver() {
/**
* Provide resolvers for custom argument types. Custom resolvers are ordered
- * after built-in ones. To override the built-in support for argument
+ * after built-in ones. To override the built-in support for argument
* resolution use {@link #setArgumentResolvers} instead.
*/
public void setCustomArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
this.customArgumentResolvers= argumentResolvers;
}
-
+
/**
* Return the custom argument resolvers, or {@code null}.
*/
@@ -120,9 +120,9 @@ public void setArgumentResolvers(List<HandlerMethodArgumentResolver> argumentRes
this.argumentResolvers.addResolvers(argumentResolvers);
}
}
-
+
/**
- * Return the configured argument resolvers, or possibly {@code null} if
+ * Return the configured argument resolvers, or possibly {@code null} if
* not initialized yet via {@link #afterPropertiesSet()}.
*/
public HandlerMethodArgumentResolverComposite getArgumentResolvers() {
@@ -146,7 +146,7 @@ public void setCustomReturnValueHandlers(List<HandlerMethodReturnValueHandler> r
}
/**
- * Configure the complete list of supported return value types thus
+ * Configure the complete list of supported return value types thus
* overriding handlers that would otherwise be configured by default.
*/
public void setReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
@@ -158,15 +158,15 @@ public void setReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnV
this.returnValueHandlers.addHandlers(returnValueHandlers);
}
}
-
+
/**
- * Return the configured handlers, or possibly {@code null} if not
+ * Return the configured handlers, or possibly {@code null} if not
* initialized yet via {@link #afterPropertiesSet()}.
*/
public HandlerMethodReturnValueHandlerComposite getReturnValueHandlers() {
return this.returnValueHandlers;
}
-
+
/**
* Set the message body converters to use.
* <p>These converters are used to convert from and to HTTP requests and responses.
@@ -174,7 +174,7 @@ public HandlerMethodReturnValueHandlerComposite getReturnValueHandlers() {
public void setMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
this.messageConverters = messageConverters;
}
-
+
/**
* Return the configured message body converters.
*/
@@ -199,11 +199,11 @@ public void afterPropertiesSet() {
*/
protected List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();
-
+
// Type-based argument resolution
resolvers.add(new ServletRequestMethodArgumentResolver());
resolvers.add(new ServletResponseMethodArgumentResolver());
-
+
// Custom arguments
if (getCustomArgumentResolvers() != null) {
resolvers.addAll(getCustomArgumentResolvers());
@@ -213,12 +213,12 @@ public void afterPropertiesSet() {
}
/**
- * Return the list of return value handlers to use including built-in and
+ * Return the list of return value handlers to use including built-in and
* custom handlers provided via {@link #setReturnValueHandlers}.
*/
protected List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
List<HandlerMethodReturnValueHandler> handlers = new ArrayList<HandlerMethodReturnValueHandler>();
-
+
// Single-purpose return value types
handlers.add(new ModelAndViewMethodReturnValueHandler());
handlers.add(new ModelMethodProcessor());
@@ -240,23 +240,18 @@ public void afterPropertiesSet() {
// Catch-all
handlers.add(new ModelAttributeMethodProcessor(true));
-
+
return handlers;
}
/**
- * Find an @{@link ExceptionHandler} method and invoke it to handle the
+ * Find an @{@link ExceptionHandler} method and invoke it to handle the
* raised exception.
*/
@Override
- protected ModelAndView doResolveHandlerMethodException(HttpServletRequest request,
- HttpServletResponse response,
- HandlerMethod handlerMethod,
- Exception exception) {
- if (handlerMethod == null) {
- return null;
- }
-
+ protected ModelAndView doResolveHandlerMethodException(HttpServletRequest request,
+ HttpServletResponse response, HandlerMethod handlerMethod, Exception exception) {
+
ServletInvocableHandlerMethod exceptionHandlerMethod = getExceptionHandlerMethod(handlerMethod, exception);
if (exceptionHandlerMethod == null) {
return null;
@@ -278,7 +273,7 @@ protected ModelAndView doResolveHandlerMethodException(HttpServletRequest reques
logger.error("Failed to invoke @ExceptionHandler method: " + exceptionHandlerMethod, invocationEx);
return null;
}
-
+
if (mavContainer.isRequestHandled()) {
return new ModelAndView();
}
@@ -288,19 +283,22 @@ protected ModelAndView doResolveHandlerMethodException(HttpServletRequest reques
if (!mavContainer.isViewReference()) {
mav.setView((View) mavContainer.getView());
}
- return mav;
+ return mav;
}
}
/**
* Find the @{@link ExceptionHandler} method for the given exception.
- * The default implementation searches @{@link ExceptionHandler} methods
+ * The default implementation searches @{@link ExceptionHandler} methods
* in the class hierarchy of the method that raised the exception.
- * @param handlerMethod the method where the exception was raised
+ * @param handlerMethod the method where the exception was raised, possibly {@code null}
* @param exception the raised exception
* @return a method to handle the exception, or {@code null}
*/
protected ServletInvocableHandlerMethod getExceptionHandlerMethod(HandlerMethod handlerMethod, Exception exception) {
+ if (handlerMethod == null) {
+ return null;
+ }
Class<?> handlerType = handlerMethod.getBeanType();
Method method = getExceptionHandlerMethodResolver(handlerType).resolveMethod(exception);
return (method != null ? new ServletInvocableHandlerMethod(handlerMethod.getBean(), method) : null);
View
2  .../org/springframework/web/servlet/mvc/method/annotation/ServletInvocableHandlerMethod.java
@@ -107,7 +107,7 @@ public final void invokeAndHandle(
mavContainer.setRequestHandled(false);
try {
- returnValueHandlers.handleReturnValue(returnValue, getReturnType(), mavContainer, request);
+ returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, request);
} catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
View
28 ...est/java/org/springframework/web/servlet/mvc/condition/ConsumesRequestConditionTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2011 the original author or authors.
+ * Copyright 2002-2012 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,7 +44,7 @@ public void consumesMatch() {
assertNotNull(condition.getMatchingCondition(request));
}
-
+
@Test
public void negatedConsumesMatch() {
ConsumesRequestCondition condition = new ConsumesRequestCondition("!text/plain");
@@ -60,7 +60,7 @@ public void getConsumableMediaTypesNegatedExpression() {
ConsumesRequestCondition condition = new ConsumesRequestCondition("!application/xml");
assertEquals(Collections.emptySet(), condition.getConsumableMediaTypes());
}
-
+
@Test
public void consumesWildcardMatch() {
ConsumesRequestCondition condition = new ConsumesRequestCondition("text/*");
@@ -92,6 +92,26 @@ public void consumesSingleNoMatch() {
}
@Test
+ public void consumesParseError() {
+ ConsumesRequestCondition condition = new ConsumesRequestCondition("text/plain");
+
+ MockHttpServletRequest request = new MockHttpServletRequest();
+ request.setContentType("01");
+
+ assertNull(condition.getMatchingCondition(request));
+ }
+
+ @Test
+ public void consumesParseErrorWithNegation() {
+ ConsumesRequestCondition condition = new ConsumesRequestCondition("!text/plain");
+
+ MockHttpServletRequest request = new MockHttpServletRequest();
+ request.setContentType("01");
+
+ assertNull(condition.getMatchingCondition(request));
+ }
+
+ @Test
public void compareToSingle() {
MockHttpServletRequest request = new MockHttpServletRequest();
@@ -128,7 +148,7 @@ public void combine() {
ConsumesRequestCondition result = condition1.combine(condition2);
assertEquals(condition2, result);
}
-
+
@Test
public void combineWithDefault() {
ConsumesRequestCondition condition1 = new ConsumesRequestCondition("text/plain");
View
38 ...est/java/org/springframework/web/servlet/mvc/condition/ProducesRequestConditionTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2011 the original author or authors.
+ * Copyright 2002-2012 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.
@@ -34,7 +34,7 @@
* @author Rossen Stoyanchev
*/
public class ProducesRequestConditionTests {
-
+
@Test
public void producesMatch() {
ProducesRequestCondition condition = new ProducesRequestCondition("text/plain");
@@ -44,7 +44,7 @@ public void producesMatch() {
assertNotNull(condition.getMatchingCondition(request));
}
-
+
@Test
public void negatedProducesMatch() {
ProducesRequestCondition condition = new ProducesRequestCondition("!text/plain");
@@ -60,7 +60,7 @@ public void getProducibleMediaTypesNegatedExpression() {
ProducesRequestCondition condition = new ProducesRequestCondition("!application/xml");
assertEquals(Collections.emptySet(), condition.getProducibleMediaTypes());
}
-
+
@Test
public void producesWildcardMatch() {
ProducesRequestCondition condition = new ProducesRequestCondition("text/*");
@@ -92,6 +92,26 @@ public void producesSingleNoMatch() {
}
@Test
+ public void producesParseError() {
+ ProducesRequestCondition condition = new ProducesRequestCondition("text/plain");
+
+ MockHttpServletRequest request = new MockHttpServletRequest();
+ request.addHeader("Accept", "bogus");
+
+ assertNull(condition.getMatchingCondition(request));
+ }
+
+ @Test
+ public void producesParseErrorWithNegation() {
+ ProducesRequestCondition condition = new ProducesRequestCondition("!text/plain");
+
+ MockHttpServletRequest request = new MockHttpServletRequest();
+ request.addHeader("Accept", "bogus");
+
+ assertNull(condition.getMatchingCondition(request));
+ }
+
+ @Test
public void compareTo() {
ProducesRequestCondition html = new ProducesRequestCondition("text/html");
ProducesRequestCondition xml = new ProducesRequestCondition("application/xml");
@@ -126,12 +146,12 @@ public void compareTo() {
assertTrue(html.compareTo(xml, request) > 0);
assertTrue(xml.compareTo(html, request) < 0);
}
-
+
@Test
public void compareToWithSingleExpression() {
MockHttpServletRequest request = new MockHttpServletRequest();
request.addHeader("Accept", "text/plain");
-
+
ProducesRequestCondition condition1 = new ProducesRequestCondition("text/plain");
ProducesRequestCondition condition2 = new ProducesRequestCondition("text/*");
@@ -188,7 +208,7 @@ public void compareToMultipleExpressionsAndMultipeAcceptHeaderValues() {
@Test
public void compareToMediaTypeAll() {
MockHttpServletRequest request = new MockHttpServletRequest();
-
+
ProducesRequestCondition condition1 = new ProducesRequestCondition();
ProducesRequestCondition condition2 = new ProducesRequestCondition("application/json");
@@ -202,7 +222,7 @@ public void compareToMediaTypeAll() {
assertTrue(condition1.compareTo(condition2, request) < 0);
assertTrue(condition2.compareTo(condition1, request) > 0);
-
+
request.addHeader("Accept", "*/*");
condition1 = new ProducesRequestCondition();
@@ -255,7 +275,7 @@ public void combine() {
ProducesRequestCondition result = condition1.combine(condition2);
assertEquals(condition2, result);
}
-
+
@Test
public void combineWithDefault() {
ProducesRequestCondition condition1 = new ProducesRequestCondition("text/plain");
View
31 .../test/java/org/springframework/web/servlet/mvc/condition/RequestConditionHolderTests.java
@@ -17,6 +17,7 @@
package org.springframework.web.servlet.mvc.condition;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import javax.servlet.http.HttpServletRequest;
@@ -24,15 +25,11 @@
import org.junit.Test;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.servlet.mvc.condition.HeadersRequestCondition;
-import org.springframework.web.servlet.mvc.condition.ParamsRequestCondition;
-import org.springframework.web.servlet.mvc.condition.RequestConditionHolder;
-import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
/**
- * A test fixture for
+ * A test fixture for
* {code org.springframework.web.servlet.mvc.method.RequestConditionHolder} tests.
- *
+ *
* @author Rossen Stoyanchev
*/
public class RequestConditionHolderTests {
@@ -41,7 +38,7 @@
public void combineEmpty() {
RequestConditionHolder empty = new RequestConditionHolder(null);
RequestConditionHolder notEmpty = new RequestConditionHolder(new ParamsRequestCondition("name"));
-
+
assertSame(empty, empty.combine(new RequestConditionHolder(null)));
assertSame(notEmpty, notEmpty.combine(empty));
assertSame(notEmpty, empty.combine(notEmpty));
@@ -52,7 +49,7 @@ public void combine() {
RequestConditionHolder params1 = new RequestConditionHolder(new ParamsRequestCondition("name1"));
RequestConditionHolder params2 = new RequestConditionHolder(new ParamsRequestCondition("name2"));
RequestConditionHolder expected = new RequestConditionHolder(new ParamsRequestCondition("name1", "name2"));
-
+
assertEquals(expected, params1.combine(params2));
}
@@ -67,14 +64,24 @@ public void combineIncompatible() {
public void match() {
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/");
request.setParameter("name1", "value1");
-
+
RequestMethodsRequestCondition rm = new RequestMethodsRequestCondition(RequestMethod.GET, RequestMethod.POST);
RequestConditionHolder custom = new RequestConditionHolder(rm);
RequestMethodsRequestCondition expected = new RequestMethodsRequestCondition(RequestMethod.GET);
-
+
assertEquals(expected, custom.getMatchingCondition(request).getCondition());
}
-
+
+ @Test
+ public void noMatch() {
+ MockHttpServletRequest request = new MockHttpServletRequest("GET", "/");
+
+ RequestMethodsRequestCondition rm = new RequestMethodsRequestCondition(RequestMethod.POST);
+ RequestConditionHolder custom = new RequestConditionHolder(rm);
+
+ assertNull(custom.getMatchingCondition(request));
+ }
+
@Test
public void matchEmpty() {
RequestConditionHolder empty = new RequestConditionHolder(null);
@@ -91,7 +98,7 @@ public void compare() {
assertEquals(1, params11.compareTo(params12, request));
assertEquals(-1, params12.compareTo(params11, request));
}
-
+
@Test
public void compareEmpty() {
HttpServletRequest request = new MockHttpServletRequest();
View
21 ...org/springframework/web/servlet/mvc/method/annotation/HttpEntityMethodProcessorTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2011 the original author or authors.
+ * Copyright 2002-2012 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,7 +56,7 @@
/**
* Test fixture with {@link HttpEntityMethodProcessor} and mock {@link HttpMessageConverter}.
- *
+ *
* @author Arjen Poutsma
* @author Rossen Stoyanchev
*/
@@ -106,7 +106,7 @@ public void setUp() throws Exception {
returnTypeResponseEntityProduces = new MethodParameter(getClass().getMethod("handle4"), -1);
mavContainer = new ModelAndViewContainer();
-
+
servletRequest = new MockHttpServletRequest();
servletResponse = new MockHttpServletResponse();
webRequest = new ServletWebRequest(servletRequest, servletResponse);
@@ -219,7 +219,7 @@ public void handleReturnValueNotAcceptable() throws Exception {
fail("Expected exception");
}
-
+
@Test(expected = HttpMediaTypeNotAcceptableException.class)
public void handleReturnValueNotAcceptableProduces() throws Exception {
String body = "Foo";
@@ -238,6 +238,17 @@ public void handleReturnValueNotAcceptableProduces() throws Exception {
fail("Expected exception");
}
+ // SPR-9142
+
+ @Test(expected=HttpMediaTypeNotAcceptableException.class)
+ public void handleReturnValueNotAcceptableParseError() throws Exception {
+ ResponseEntity<String> returnValue = new ResponseEntity<String>("Body", HttpStatus.ACCEPTED);
+ servletRequest.addHeader("Accept", "01");
+
+ processor.handleReturnValue(returnValue, returnTypeResponseEntity, mavContainer, webRequest);
+ fail("Expected exception");
+ }
+
@Test
public void responseHeaderNoBody() throws Exception {
HttpHeaders headers = new HttpHeaders();
@@ -269,7 +280,7 @@ public void responseHeaderAndBody() throws Exception {
assertEquals("headerValue", outputMessage.getValue().getHeaders().get("header").get(0));
verify(messageConverter);
}
-
+
public ResponseEntity<String> handle1(HttpEntity<String> httpEntity, ResponseEntity<String> responseEntity, int i) {
return responseEntity;
}
View
64 ...springframework/web/servlet/mvc/method/annotation/ServletInvocableHandlerMethodTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2011 the original author or authors.
+ * Copyright 2002-2012 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.
@@ -15,9 +15,10 @@
*/
package org.springframework.web.servlet.mvc.method.annotation;
-import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import java.lang.reflect.Method;
@@ -30,17 +31,20 @@
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
+import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.ServletWebRequest;
+import org.springframework.web.method.annotation.RequestParamMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodArgumentResolverComposite;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite;
import org.springframework.web.method.support.ModelAndViewContainer;
+import org.springframework.web.servlet.view.RedirectView;
/**
* Test fixture with {@link ServletInvocableHandlerMethod}.
- *
+ *
* @author Rossen Stoyanchev
*/
public class ServletInvocableHandlerMethodTests {
@@ -53,6 +57,8 @@
private ServletWebRequest webRequest;
+ private MockHttpServletRequest request;
+
private MockHttpServletResponse response;
@Before
@@ -60,8 +66,9 @@ public void setUp() throws Exception {
returnValueHandlers = new HandlerMethodReturnValueHandlerComposite();
argumentResolvers = new HandlerMethodArgumentResolverComposite();
mavContainer = new ModelAndViewContainer();
+ request = new MockHttpServletRequest();
response = new MockHttpServletResponse();
- webRequest = new ServletWebRequest(new MockHttpServletRequest(), response);
+ webRequest = new ServletWebRequest(request, response);
}
@Test
@@ -92,29 +99,45 @@ public void nullReturnValueRequestNotModified() throws Exception {
webRequest.getNativeRequest(MockHttpServletRequest.class).addHeader("If-Modified-Since", 10 * 1000 * 1000);
int lastModifiedTimestamp = 1000 * 1000;
webRequest.checkNotModified(lastModifiedTimestamp);
-
+
ServletInvocableHandlerMethod handlerMethod = getHandlerMethod("notModified");
handlerMethod.invokeAndHandle(webRequest, mavContainer);
assertTrue("Null return value + 'not modified' request should result in 'request handled'",
mavContainer.isRequestHandled());
}
-
- @Test
+
+ @Test(expected=HttpMessageNotWritableException.class)
public void exceptionWhileHandlingReturnValue() throws Exception {
returnValueHandlers.addHandler(new ExceptionRaisingReturnValueHandler());
ServletInvocableHandlerMethod handlerMethod = getHandlerMethod("handle");
- try {
- handlerMethod.invokeAndHandle(webRequest, mavContainer);
- fail("Expected exception");
- } catch (HttpMessageNotWritableException ex) {
- // Expected..
- // Allow HandlerMethodArgumentResolver exceptions to propagate..
- }
+ handlerMethod.invokeAndHandle(webRequest, mavContainer);
+ fail("Expected exception");
}
- private ServletInvocableHandlerMethod getHandlerMethod(String methodName, Class<?>... argTypes)
+ @Test
+ public void dynamicReturnValue() throws Exception {
+ argumentResolvers.addResolver(new RequestParamMethodArgumentResolver(null, false));
+ returnValueHandlers.addHandler(new ViewMethodReturnValueHandler());
+ returnValueHandlers.addHandler(new ViewNameMethodReturnValueHandler());
+
+ // Invoke without a request parameter (String return value)
+ ServletInvocableHandlerMethod handlerMethod = getHandlerMethod("dynamicReturnValue", String.class);
+ handlerMethod.invokeAndHandle(webRequest, mavContainer);
+
+ assertNotNull(mavContainer.getView());
+ assertEquals(RedirectView.class, mavContainer.getView().getClass());
+
+ // Invoke with a request parameter (RedirectView return value)
+ request.setParameter("param", "value");
+ handlerMethod.invokeAndHandle(webRequest, mavContainer);
+
+ assertEquals("view", mavContainer.getViewName());
+ }
+
+
+ private ServletInvocableHandlerMethod getHandlerMethod(String methodName, Class<?>... argTypes)
throws NoSuchMethodException {
Method method = Handler.class.getDeclaredMethod(methodName, argTypes);
ServletInvocableHandlerMethod handlerMethod = new ServletInvocableHandlerMethod(new Handler(), method);
@@ -133,13 +156,16 @@ public String handle() {
@ResponseStatus(value = HttpStatus.BAD_REQUEST, reason = "400 Bad Request")
public void responseStatus() {
}
-
+
public void httpServletResponse(HttpServletResponse response) {
}
-
+
public void notModified() {
}
-
+
+ public Object dynamicReturnValue(@RequestParam(required=false) String param) {
+ return (param != null) ? "view" : new RedirectView("redirectView");
+ }
}
private static class ExceptionRaisingReturnValueHandler implements HandlerMethodReturnValueHandler {
View