Rectangle 27 0

java Spring MVC @PathVariable getting truncated?


+1 for a great answer and also for using the phrase "molesting your data"

As described in the linked issue, you can disable this behaviour by declaring your own DefaultAnnotationHandlerMapping bean in the app context, and setting its useDefaultSuffixPattern property to false. This will override the default behaviour, and stop it molesting your data.

For Spring 3.1 users - if you're using the new RequestMappingHandlerMapping instead, the property to set is useSuffixPatternMatch (also to false). @Ted: the linked issue mentions that in 3.2 they hope to add a bit more control so it doesn't have to be all-or-nothing.

In Spring 4.2 this is slightly easier to configure. We use Java config classes and extend the WebMvcConfigurationSupport which provides a simple hook:public void configurePathMatch(PathMatchConfigurer configurer) - just override that and set up the path matching how you like.

This is probably closely related to SPR-6164. Briefly, the framework tries to apply some smarts to the URI interpretation, removing what it thinks are file extensions. This would have the effect of turning blah2010.08.19-02:25:47 into blah2010.08, since it thinks the .19-02:25:47 is a file extension.

This worked for me with a similar problem. Thanks, skaffman.

Turning extension based content negotiation on by default seems like such a strange choice. How many systems really expose the same resource in different formats in practice?

Note
Rectangle 27 0

java Spring MVC @PathVariable getting truncated?


RequestMapping(method = RequestMethod.GET, value = Routes.BLAH_GET + "/{blahName:.+}")

Sign up for our newsletter and get our top new questions delivered to your inbox (see an example).

Noah, I haven't used this in a long time, but I think the colon separates the regular expression from the argument name to bind it to.

Thanks for the answer, this helped me solve a case where usernames got trimmed somehow .. (-: The other option with 'useDefaultSuffixPattern' was not an option because we're using @Configuration spring classes instead of XML.

This works, but what is the significance of the colon in the regex?

Try a regular expression for the @RequestMapping argument:

we had a similar problam /item/user@abc.com, anything after @ was truncated, this was solved by adding another slash /item/user@abc.com/

Note
Rectangle 27 0

java Spring MVC @PathVariable getting truncated?


/param
/param.anything
/param.json
/param.value.anything
/param.value.json
/param.value.xml
/param.xml
/{blahName}
<bean id="handlerMapping"
      class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
    <property name="contentNegotiationManager" ref="contentNegotiationManager"/>
    <property name="useRegisteredSuffixPatternMatch" value="true"/>
</bean>

<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
    <property name="favorPathExtension" value="false"/>
    <property name="favorParameter" value="true"/>
    <property name="mediaTypes">
        <value>
            json=application/json
            xml=application/xml
        </value>
    </property>
</bean>
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean" />

<util:list id="messageConverters">
    <bean class="your.custom.message.converter.IfAny"></bean>
    <bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"></bean>
    <bean class="org.springframework.http.converter.StringHttpMessageConverter"></bean>
    <bean class="org.springframework.http.converter.ResourceHttpMessageConverter"></bean>
    <bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter"></bean>
    <bean class="org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter"></bean>
    <bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter"></bean>
    <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
</util:list>

<bean name="exceptionHandlerExceptionResolver"
      class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver">
    <property name="order" value="0"/>
    <property name="messageConverters" ref="messageConverters"/>
</bean>

<bean name="handlerAdapter"
      class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
    <property name="webBindingInitializer">
        <bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
            <property name="conversionService" ref="conversionService" />
            <property name="validator" ref="validator" />
        </bean>
    </property>
    <property name="messageConverters" ref="messageConverters"/>
</bean>

<bean id="handlerMapping"
      class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
</bean>
param
param.anything
param.value
param.value.json
  • /param will result in a param with value param
  • /param.json will result in a param with value param.json
  • /param.xml will result in a param with value param.xml

For that reason, you still have to override all the mvc:annotation-driven configuration. I opened a ticket to Spring to ask for a custom RequestMappingHandlerMapping: https://jira.springsource.org/browse/SPR-11253. Please vote if you are interested in.

Here you define only json and xml extensions:

If you change your mapping to /{blahName:.+} as suggested, any dot, including the last one, will be considered as part of your parameter:

If you don't care of extension recognition, you can disable it by overriding mvc:annotation-driven automagic:

If you want to keep extension management, since Spring 3.2 you can also set the useRegisteredSuffixPatternMatch property of RequestMappingHandlerMapping bean in order to keep suffixPattern recognition activated but limited to registered extension.

Note that mvc:annotation-driven accepts now a contentNegotiation option to provide a custom bean but the property of RequestMappingHandlerMapping has to be changed to true (default false) (cf. https://jira.springsource.org/browse/SPR-7632).

Note: the difference from the default config is visible only if you have a mapping like /something.{blahName}. See Resthub project issue.

So, again, if you have /{blahName}:

Spring considers that anything behind the last dot is a file extension such as .jsonor .xml and truncate it to retrieve your parameter.

While overriding, be careful to consider also custom Execution management overriding. Otherwise, all your custom Exception mappings will fail. You will have to reuse messageCoverters with a list bean:

Note
Rectangle 27 0

java Spring MVC @PathVariable getting truncated?


<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
    <property name="useDefaultSuffixPattern" value="false" />
</bean>

Everything after the last dot is interpreted as file extension and cut off by default. In your spring config xml you can add DefaultAnnotationHandlerMapping and set useDefaultSuffixPattern to false (default is true).

I have not tried, but others claim you'd then also need to remove <mvc:annotation-driven /> if applicable.

Now your @PathVariable blahName (and all other, too) should contain the full name including all dots.

So open your spring xml mvc-config.xml (or however it is called) and add

Note
Rectangle 27 0

java Spring MVC @PathVariable getting truncated?


RequestMapping(method = RequestMethod.GET, value = Routes.BLAH_GET + "/{blahName:.+}")

Noah, I haven't used this in a long time, but I think the colon separates the regular expression from the argument name to bind it to.

Thanks for the answer, this helped me solve a case where usernames got trimmed somehow .. (-: The other option with 'useDefaultSuffixPattern' was not an option because we're using @Configuration spring classes instead of XML.

This works, but what is the significance of the colon in the regex?

Try a regular expression for the @RequestMapping argument:

we had a similar problam /item/user@abc.com, anything after @ was truncated, this was solved by adding another slash /item/user@abc.com/

Note
Rectangle 27 0

java Spring MVC @PathVariable getting truncated?


BTW, I don't know what the Spring designers were thinking when they added this "feature" and then turned it on by default. IMHO, it should be removed.

I also ran into the same issue, and setting the property to false didn't help me either. However, the API says:

I tried adding "/end" to my RESTful URL, and the problem went away. I'm not please with the solution, but it did work.

Note that paths which include a ".xxx" suffix or end with "/" already will not be transformed using the default suffix pattern in any case.

Note
Rectangle 27 0

java Spring MVC @PathVariable getting truncated?


+1 for a great answer and also for using the phrase "molesting your data"

As described in the linked issue, you can disable this behaviour by declaring your own DefaultAnnotationHandlerMapping bean in the app context, and setting its useDefaultSuffixPattern property to false. This will override the default behaviour, and stop it molesting your data.

For Spring 3.1 users - if you're using the new RequestMappingHandlerMapping instead, the property to set is useSuffixPatternMatch (also to false). @Ted: the linked issue mentions that in 3.2 they hope to add a bit more control so it doesn't have to be all-or-nothing.

In Spring 4.2 this is slightly easier to configure. We use Java config classes and extend the WebMvcConfigurationSupport which provides a simple hook:public void configurePathMatch(PathMatchConfigurer configurer) - just override that and set up the path matching how you like.

This is probably closely related to SPR-6164. Briefly, the framework tries to apply some smarts to the URI interpretation, removing what it thinks are file extensions. This would have the effect of turning blah2010.08.19-02:25:47 into blah2010.08, since it thinks the .19-02:25:47 is a file extension.

This worked for me with a similar problem. Thanks, skaffman.

Turning extension based content negotiation on by default seems like such a strange choice. How many systems really expose the same resource in different formats in practice?

Note
Rectangle 27 0

java Spring MVC @PathVariable getting truncated?


<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
    <property name="useDefaultSuffixPattern" value="false" />
</bean>

Everything after the last dot is interpreted as file extension and cut off by default. In your spring config xml you can add DefaultAnnotationHandlerMapping and set useDefaultSuffixPattern to false (default is true).

I have not tried, but others claim you'd then also need to remove <mvc:annotation-driven /> if applicable.

Now your @PathVariable blahName (and all other, too) should contain the full name including all dots.

So open your spring xml mvc-config.xml (or however it is called) and add

Note
Rectangle 27 0

java Spring MVC @PathVariable getting truncated?


/param
/param.anything
/param.json
/param.value.anything
/param.value.json
/param.value.xml
/param.xml
/{blahName}
<bean id="handlerMapping"
      class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
    <property name="contentNegotiationManager" ref="contentNegotiationManager"/>
    <property name="useRegisteredSuffixPatternMatch" value="true"/>
</bean>

<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
    <property name="favorPathExtension" value="false"/>
    <property name="favorParameter" value="true"/>
    <property name="mediaTypes">
        <value>
            json=application/json
            xml=application/xml
        </value>
    </property>
</bean>
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean" />

<util:list id="messageConverters">
    <bean class="your.custom.message.converter.IfAny"></bean>
    <bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"></bean>
    <bean class="org.springframework.http.converter.StringHttpMessageConverter"></bean>
    <bean class="org.springframework.http.converter.ResourceHttpMessageConverter"></bean>
    <bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter"></bean>
    <bean class="org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter"></bean>
    <bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter"></bean>
    <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
</util:list>

<bean name="exceptionHandlerExceptionResolver"
      class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver">
    <property name="order" value="0"/>
    <property name="messageConverters" ref="messageConverters"/>
</bean>

<bean name="handlerAdapter"
      class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
    <property name="webBindingInitializer">
        <bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
            <property name="conversionService" ref="conversionService" />
            <property name="validator" ref="validator" />
        </bean>
    </property>
    <property name="messageConverters" ref="messageConverters"/>
</bean>

<bean id="handlerMapping"
      class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
</bean>
param
param.anything
param.value
param.value.json
  • /param will result in a param with value param
  • /param.json will result in a param with value param.json
  • /param.xml will result in a param with value param.xml

For that reason, you still have to override all the mvc:annotation-driven configuration. I opened a ticket to Spring to ask for a custom RequestMappingHandlerMapping: https://jira.springsource.org/browse/SPR-11253. Please vote if you are interested in.

Here you define only json and xml extensions:

If you change your mapping to /{blahName:.+} as suggested, any dot, including the last one, will be considered as part of your parameter:

If you don't care of extension recognition, you can disable it by overriding mvc:annotation-driven automagic:

If you want to keep extension management, since Spring 3.2 you can also set the useRegisteredSuffixPatternMatch property of RequestMappingHandlerMapping bean in order to keep suffixPattern recognition activated but limited to registered extension.

Note that mvc:annotation-driven accepts now a contentNegotiation option to provide a custom bean but the property of RequestMappingHandlerMapping has to be changed to true (default false) (cf. https://jira.springsource.org/browse/SPR-7632).

Note: the difference from the default config is visible only if you have a mapping like /something.{blahName}. See Resthub project issue.

So, again, if you have /{blahName}:

Spring considers that anything behind the last dot is a file extension such as .jsonor .xml and truncate it to retrieve your parameter.

While overriding, be careful to consider also custom Execution management overriding. Otherwise, all your custom Exception mappings will fail. You will have to reuse messageCoverters with a list bean:

Note
Rectangle 27 0

java Spring MVC @PathVariable getting truncated?


@PathVariable("requestParam") String requestParam, HttpServletRequest request) throws Exception {
request.getPathInfo()

2) Get the URL directly (At this level no truncation) in the request

Note