Browse Source

Reinstate removal of semicolon content

Commit 5b1165 was an attempt to leave semicolon content in the URL path
while ignoring it for request mapping purposes. However, it becomes
quite difficult to manage and semicolon content should not always be
ignored (sometimes a semicolon is used as a separator of multiple items
in a path segment, rather than for matrix variables).

This change effectively reverts back to the original approach in 3.2
where a flag on AbstractHandlerMapping can be used to have semicolon
content removed or kept. If kept, path segments with matrix variables
must be represented with a path segment.

The main difference is that by default it is removed everywhere
including the MVC namespace and Java config.

Issue: SPR-10427, SPR-10234
pull/292/head
Rossen Stoyanchev 13 years ago
parent
commit
d23de282a6
  1. 4
      spring-webmvc/src/main/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParser.java
  2. 2
      spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMapping.java
  3. 8
      spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodMapping.java
  4. 12
      spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/PatternsRequestCondition.java
  5. 11
      spring-webmvc/src/main/resources/org/springframework/web/servlet/config/spring-mvc-3.2.xsd
  6. 11
      spring-webmvc/src/main/resources/org/springframework/web/servlet/config/spring-mvc-4.0.xsd
  7. 15
      spring-webmvc/src/test/java/org/springframework/web/servlet/config/MvcNamespaceTests.java
  8. 17
      spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/condition/PatternsRequestConditionTests.java
  9. 10
      spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/RequestMappingInfoHandlerMappingTests.java
  10. 5
      spring-webmvc/src/test/resources/org/springframework/web/servlet/config/mvc-config-custom-validator.xml
  11. 4
      src/reference/docbook/mvc.xml

4
spring-webmvc/src/main/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParser.java

@ -157,6 +157,10 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
handlerMappingDef.getPropertyValues().add("order", 0); handlerMappingDef.getPropertyValues().add("order", 0);
handlerMappingDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager); handlerMappingDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
String methodMappingName = parserContext.getReaderContext().registerWithGeneratedName(handlerMappingDef); String methodMappingName = parserContext.getReaderContext().registerWithGeneratedName(handlerMappingDef);
if (element.hasAttribute("enableMatrixVariables")) {
Boolean enableMatrixVariables = Boolean.valueOf(element.getAttribute("enableMatrixVariables"));
handlerMappingDef.getPropertyValues().add("removeSemicolonContent", !enableMatrixVariables);
}
RuntimeBeanReference conversionService = getConversionService(element, source, parserContext); RuntimeBeanReference conversionService = getConversionService(element, source, parserContext);
RuntimeBeanReference validator = getValidator(element, source, parserContext); RuntimeBeanReference validator = getValidator(element, source, parserContext);

2
spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMapping.java

@ -128,7 +128,7 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
/** /**
* Set if ";" (semicolon) content should be stripped from the request URI. * Set if ";" (semicolon) content should be stripped from the request URI.
* <p>The default value is {@code false}. * <p>The default value is {@code true}.
* @see org.springframework.web.util.UrlPathHelper#setRemoveSemicolonContent(boolean) * @see org.springframework.web.util.UrlPathHelper#setRemoveSemicolonContent(boolean)
*/ */
public void setRemoveSemicolonContent(boolean removeSemicolonContent) { public void setRemoveSemicolonContent(boolean removeSemicolonContent) {

8
spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodMapping.java

@ -25,6 +25,7 @@ import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@ -37,7 +38,6 @@ import org.springframework.util.ReflectionUtils.MethodFilter;
import org.springframework.web.method.HandlerMethod; import org.springframework.web.method.HandlerMethod;
import org.springframework.web.method.HandlerMethodSelector; import org.springframework.web.method.HandlerMethodSelector;
import org.springframework.web.servlet.HandlerMapping; import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.util.UrlPathHelper;
/** /**
* Abstract base class for {@link HandlerMapping} implementations that define a * Abstract base class for {@link HandlerMapping} implementations that define a
@ -62,12 +62,6 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
private final MultiValueMap<String, T> urlMap = new LinkedMultiValueMap<String, T>(); private final MultiValueMap<String, T> urlMap = new LinkedMultiValueMap<String, T>();
public AbstractHandlerMethodMapping() {
UrlPathHelper pathHelper = new UrlPathHelper();
pathHelper.setRemoveSemicolonContent(false);
setUrlPathHelper(pathHelper);
}
/** /**
* Whether to detect handler methods in beans in ancestor ApplicationContexts. * Whether to detect handler methods in beans in ancestor ApplicationContexts.
* <p>Default is "false": Only beans in the current ApplicationContext are * <p>Default is "false": Only beans in the current ApplicationContext are

12
spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/PatternsRequestCondition.java

@ -42,13 +42,6 @@ import org.springframework.web.util.UrlPathHelper;
*/ */
public final class PatternsRequestCondition extends AbstractRequestCondition<PatternsRequestCondition> { public final class PatternsRequestCondition extends AbstractRequestCondition<PatternsRequestCondition> {
private static UrlPathHelper pathHelperNoSemicolonContent;
static {
pathHelperNoSemicolonContent = new UrlPathHelper();
pathHelperNoSemicolonContent.setRemoveSemicolonContent(true);
}
private final Set<String> patterns; private final Set<String> patterns;
private final UrlPathHelper pathHelper; private final UrlPathHelper pathHelper;
@ -217,15 +210,10 @@ public final class PatternsRequestCondition extends AbstractRequestCondition<Pat
} }
String lookupPath = this.pathHelper.getLookupPathForRequest(request); String lookupPath = this.pathHelper.getLookupPathForRequest(request);
String lookupPathNoSemicolonContent = (lookupPath.indexOf(';') != -1) ?
pathHelperNoSemicolonContent.getLookupPathForRequest(request) : null;
List<String> matches = new ArrayList<String>(); List<String> matches = new ArrayList<String>();
for (String pattern : patterns) { for (String pattern : patterns) {
String match = getMatchingPattern(pattern, lookupPath); String match = getMatchingPattern(pattern, lookupPath);
if (match == null && lookupPathNoSemicolonContent != null) {
match = getMatchingPattern(pattern, lookupPathNoSemicolonContent);
}
if (match != null) { if (match != null) {
matches.add(match); matches.add(match);
} }

11
spring-webmvc/src/main/resources/org/springframework/web/servlet/config/spring-mvc-3.2.xsd

@ -231,6 +231,17 @@
</xsd:appinfo> </xsd:appinfo>
</xsd:annotation> </xsd:annotation>
</xsd:attribute> </xsd:attribute>
<xsd:attribute name="enableMatrixVariables" type="xsd:boolean">
<xsd:annotation>
<xsd:documentation><![CDATA[
Matrix variables can appear in any path segment, each matrix variable separated with a ";" (semicolon).
For example "/cars;color=red;year=2012". By default they're removed from the URL. If this property
is set to true, matrix variables are not removed from the URL, and the request mapping pattern
must use URI variable in path segments where matrix variables are expected. For example "/{cars}".
Matrix variables can then be injected into a controller method with @MatrixVariable.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="ignoreDefaultModelOnRedirect" type="xsd:boolean"> <xsd:attribute name="ignoreDefaultModelOnRedirect" type="xsd:boolean">
<xsd:annotation> <xsd:annotation>
<xsd:documentation><![CDATA[ <xsd:documentation><![CDATA[

11
spring-webmvc/src/main/resources/org/springframework/web/servlet/config/spring-mvc-4.0.xsd

@ -231,6 +231,17 @@
</xsd:appinfo> </xsd:appinfo>
</xsd:annotation> </xsd:annotation>
</xsd:attribute> </xsd:attribute>
<xsd:attribute name="enableMatrixVariables" type="xsd:boolean">
<xsd:annotation>
<xsd:documentation><![CDATA[
Matrix variables can appear in any path segment, each matrix variable separated with a ";" (semicolon).
For example "/cars;color=red;year=2012". By default they're removed from the URL. If this property
is set to true, matrix variables are not removed from the URL, and the request mapping pattern
must use URI variable in path segments where matrix variables are expected. For example "/{cars}".
Matrix variables can then be injected into a controller method with @MatrixVariable.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="ignoreDefaultModelOnRedirect" type="xsd:boolean"> <xsd:attribute name="ignoreDefaultModelOnRedirect" type="xsd:boolean">
<xsd:annotation> <xsd:annotation>
<xsd:documentation><![CDATA[ <xsd:documentation><![CDATA[

15
spring-webmvc/src/test/java/org/springframework/web/servlet/config/MvcNamespaceTests.java

@ -16,13 +16,6 @@
package org.springframework.web.servlet.config; package org.springframework.web.servlet.config;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@ -30,6 +23,7 @@ import java.util.Arrays;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import javax.servlet.RequestDispatcher; import javax.servlet.RequestDispatcher;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
@ -86,6 +80,8 @@ import org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler
import org.springframework.web.servlet.resource.ResourceHttpRequestHandler; import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;
import org.springframework.web.servlet.theme.ThemeChangeInterceptor; import org.springframework.web.servlet.theme.ThemeChangeInterceptor;
import static org.junit.Assert.*;
/** /**
* @author Keith Donald * @author Keith Donald
* @author Arjen Poutsma * @author Arjen Poutsma
@ -117,6 +113,7 @@ public class MvcNamespaceTests {
RequestMappingHandlerMapping mapping = appContext.getBean(RequestMappingHandlerMapping.class); RequestMappingHandlerMapping mapping = appContext.getBean(RequestMappingHandlerMapping.class);
assertNotNull(mapping); assertNotNull(mapping);
assertEquals(0, mapping.getOrder()); assertEquals(0, mapping.getOrder());
assertTrue(mapping.getUrlPathHelper().shouldRemoveSemicolonContent());
mapping.setDefaultHandler(handlerMethod); mapping.setDefaultHandler(handlerMethod);
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo.json"); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo.json");
@ -182,6 +179,10 @@ public class MvcNamespaceTests {
public void testCustomValidator() throws Exception { public void testCustomValidator() throws Exception {
loadBeanDefinitions("mvc-config-custom-validator.xml", 12); loadBeanDefinitions("mvc-config-custom-validator.xml", 12);
RequestMappingHandlerMapping mapping = appContext.getBean(RequestMappingHandlerMapping.class);
assertNotNull(mapping);
assertFalse(mapping.getUrlPathHelper().shouldRemoveSemicolonContent());
RequestMappingHandlerAdapter adapter = appContext.getBean(RequestMappingHandlerAdapter.class); RequestMappingHandlerAdapter adapter = appContext.getBean(RequestMappingHandlerAdapter.class);
assertNotNull(adapter); assertNotNull(adapter);
assertEquals(true, new DirectFieldAccessor(adapter).getPropertyValue("ignoreDefaultModelOnRedirect")); assertEquals(true, new DirectFieldAccessor(adapter).getPropertyValue("ignoreDefaultModelOnRedirect"));

17
spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/condition/PatternsRequestConditionTests.java

@ -16,10 +16,6 @@
package org.springframework.web.servlet.mvc.condition; package org.springframework.web.servlet.mvc.condition;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@ -27,7 +23,8 @@ import javax.servlet.http.HttpServletRequest;
import org.junit.Test; import org.junit.Test;
import org.springframework.mock.web.test.MockHttpServletRequest; import org.springframework.mock.web.test.MockHttpServletRequest;
import org.springframework.web.util.UrlPathHelper;
import static org.junit.Assert.*;
/** /**
* @author Rossen Stoyanchev * @author Rossen Stoyanchev
@ -186,16 +183,6 @@ public class PatternsRequestConditionTests {
assertNull(match); assertNull(match);
} }
@Test
public void matchIgnorePathParams() {
UrlPathHelper pathHelper = new UrlPathHelper();
pathHelper.setRemoveSemicolonContent(false);
PatternsRequestCondition condition = new PatternsRequestCondition(new String[] {"/foo/bar"}, pathHelper, null, true, true);
PatternsRequestCondition match = condition.getMatchingCondition(new MockHttpServletRequest("GET", "/foo;q=1/bar;s=1"));
assertNotNull(match);
}
@Test @Test
public void compareEqualPatterns() { public void compareEqualPatterns() {
PatternsRequestCondition c1 = new PatternsRequestCondition("/foo*"); PatternsRequestCondition c1 = new PatternsRequestCondition("/foo*");

10
spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/RequestMappingInfoHandlerMappingTests.java

@ -16,13 +16,6 @@
package org.springframework.web.servlet.mvc.method; package org.springframework.web.servlet.mvc.method;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.fail;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
@ -61,6 +54,8 @@ import org.springframework.web.servlet.mvc.condition.ProducesRequestCondition;
import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition; import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
import org.springframework.web.util.UrlPathHelper; import org.springframework.web.util.UrlPathHelper;
import static org.junit.Assert.*;
/** /**
* Test fixture with {@link RequestMappingInfoHandlerMapping}. * Test fixture with {@link RequestMappingInfoHandlerMapping}.
* *
@ -90,6 +85,7 @@ public class RequestMappingInfoHandlerMappingTests {
this.handlerMapping = new TestRequestMappingInfoHandlerMapping(); this.handlerMapping = new TestRequestMappingInfoHandlerMapping();
this.handlerMapping.registerHandler(testController); this.handlerMapping.registerHandler(testController);
this.handlerMapping.setRemoveSemicolonContent(false);
} }
@Test @Test

5
spring-webmvc/src/test/resources/org/springframework/web/servlet/config/mvc-config-custom-validator.xml

@ -3,9 +3,10 @@
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd"> http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">
<mvc:annotation-driven validator="validator" ignoreDefaultModelOnRedirect="true" /> <mvc:annotation-driven validator="validator"
ignoreDefaultModelOnRedirect="true" enableMatrixVariables="true" />
<bean id="validator" class="org.springframework.web.servlet.config.MvcNamespaceTests$TestValidator" /> <bean id="validator" class="org.springframework.web.servlet.config.MvcNamespaceTests$TestValidator" />

4
src/reference/docbook/mvc.xml

@ -1173,9 +1173,7 @@ public void findPet(
<para>Note that to enable the use of matrix variables, you must set the <para>Note that to enable the use of matrix variables, you must set the
<classname>removeSemicolonContent</classname> property of <classname>removeSemicolonContent</classname> property of
<classname>RequestMappingHandlerMapping</classname> to <code>false</code>. <classname>RequestMappingHandlerMapping</classname> to <code>false</code>.
By default it is set to <code>true</code> with the exception of the By default it is set to <code>false</code>.</para>
MVC namespace and the MVC Java config both of which automatically enable
the use of matrix variables.</para>
</section> </section>

Loading…
Cancel
Save