How to change Spring MVC's behavior in handling url 'dot' character
Asked Answered
C

6

9

I'm trying to migrate a web project off from Jersey to Spring MVC 3.0. The process was really straightforward up to the moment when I started to migrate the controllers supposed to handle URL's with dot notations: "/myApp/resources/create/root.subFolder1". Spring MVC seems to shamelessly cut the ".subFolder1" part from the URL, which happens deep inside framework code (see AbstractUrlHandlerMapping class)

uriTemplateVariables.putAll(getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath));

So my controller method gets invoked with root path parameter, not root.subFolder1

I'd really like to find a way to customize this behavior. Any advices?

PS. The requirement is kinda to keep the existing URL structure, i.e. workarounds like switching to query params "/myApp/resources/create/?path=root.subFolder1" I cannot consider.

PS. My Spring config looks like

<mvc:annotation-driven/>

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

<context:component-scan base-package="my.app.pkg"/>
Centistere answered 9/11, 2010 at 15:25 Comment(1)
Btw, in the future it might be a good idea to include the Java tag, as that might get more visibility.Sinnard
T
9

Another possibility which may be easier in some circumstances is to add a trailing / to the end of the URL.

So your URL would be /myApp/resources/create/root.subFolder1/

This works in my app using Spring MVC 3.1.

Thetisa answered 6/12, 2012 at 20:52 Comment(1)
This was best solution for me. I needed the annotation tags for the rest of the site.Crutchfield
S
8

Try this:

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

This should make it so that Spring won't try to parse extensions.

See also: Spring MVC @PathVariable getting truncated

And: Spring Documentation

Potential config files:

web.xml (where I set the servlet stuff)

<servlet>
    <servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/spring/*.xml,classpath*:applicationContext.xml,classpath*:restApplicationContext.xml
        </param-value>
    </init-param>
    <load-on-startup>2</load-on-startup>
</servlet>

And then in WEB/INF/spring/mvc-config.xml I have something like this:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

    <bean
        class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
        <property name="useDefaultSuffixPattern" value="false" />
    </bean>
</beans>
Sinnard answered 9/11, 2010 at 15:31 Comment(11)
If this helped, accept it. If not, further explain the problem :)Sinnard
Should I declare this bean by itself or out is as a dependency to some other bean? Looks like just declaring it in spring servlet xml config doesn't help...Centistere
I'm assuming the servlet.xml config is where you configure the servlet. Do you use any init-param config for contextConfigLocation?Sinnard
This doesn't work for me. The reason is that this property isn't supposed to address my issue, at least the documentation clearly states that "paths which include a ".xxx" suffix or end with "/" already will not be * transformed using the default suffix pattern in any case."Centistere
Addition: when I added DefaultAnnotationHandlerMapping to a spring context, and placed two breakpoints in the code: 1) in setUseDefaultSuffixPattern() and 2) in addUrlsForPath(), both of class DefaultAnnotationHandlerMapping, it appeared that the addUrls gets invoked BEFORE setUseDefaultSuffixPattern, which might be the part of the reason why I can't override spring behaviorCentistere
I don't understand why this doesn't work for you. I had the exact same problem you are describing. I feel like though it won't get transformed it's still going to look for a content negotiator of "subFolder1" which it obviously won't find. Maybe you could share the whole of your servlet xml file?Sinnard
The weird thing I notice from logs is that actual url mapping happens TWICE: [INFO ][.DefaultAnnotationHandlerMapping] - Mapped URL path [/available/{userId}] onto handler 'userConnector' [INFO ][.DefaultAnnotationHandlerMapping] - Mapped URL path [/available/{userId}.*] onto handler 'userConnector' [INFO ][.DefaultAnnotationHandlerMapping] - Mapped URL path [/available/{userId}/] onto handler 'userConnector' [INFO ][.DefaultAnnotationHandlerMapping] - Mapped URL path [/available/{userId}] onto handler 'userConnector'Centistere
Try taking out the mvnc:annotation-driven line and see what happens.Sinnard
I'm almost certain either mvc:annotation-driven or context:component-scan is overwriting the DefaultAnnotationHandlerMapping that you're trying to add in.Sinnard
Well, indeed it's the mvc:annotation-driven which causeing the problems. But how to setup annotation support without it?Centistere
Well, here is what it does: rapid-web.tumblr.com/post/296916668/… Perhaps from that you can determine what you need to use to make things work. I've never used the annotation-driven config because of these types of problems so I usually set things up just for what I need.Sinnard
N
2

In order for

<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />

to work you have to remove/comment out the

<mvc:annotation-driven />
<mvc:default-servlet-handler />

and any other mvc: configurations defined as they override your custom bean declarations.

Nonbelligerent answered 21/6, 2012 at 15:10 Comment(0)
R
1

This was a bitch. A guy on our team here got it to work over the weekend. We were going to go with underscore but he got it. He removed @Controller from the controller class attributes and left @RequestMapping blank for the class. On the public methods for Http get and put he added "/2.0/" to the @RequestMapping. Example below.

@RequestMapping
public class EndpointController {

@RequestMapping(value="/2.0/endpoint", method = RequestMethod.POST,
consumes=MediaType.APPLICATION_JSON_VALUE, produces=MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<EndpointView> create( @Valid @RequestBody EndpointView endpointParams, HttpServletRequest request )

Good luck everyone. This problem sucked.

Robet answered 16/1, 2013 at 18:30 Comment(0)
N
1

I did almost the same as Robert Beltran but I left @Controller annotation for the class. Important is to put "/1.0/" to the @RequestMapping on the methods, not in class annotation.
My example:

@Controller
@RequestMapping("")
public class ClientApi {

private final String API_PREFIX = "/api/1.0/client";

@RequestMapping(value = API_PREFIX + "/{clientId}", method = RequestMethod.GET)
@ResponseBody
public ClientDetailsImpl get(@PathVariable String clientId) {
    // my code
}
}
Narwhal answered 11/2, 2014 at 0:14 Comment(1)
I just saw this because we got hit again. Different project. Thanks!Robet
R
0

The above answer should correct, but be sure to remove <mvc:annotation-driven/> from your XML configuration, otherwise the bean definition is overruled by the one part of the annotation-driven tag.

See the java docs and the source code for all the configuration you miss when this convenience tag is removed.

Rodrickrodrigez answered 30/9, 2011 at 9:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.