14

In my Spring controller, I try to get 3 path variables:

@RequestMapping("{language}/{country}/{term}/catalogue") - @PathVariable String language, @PathVariable String country, @PathVariable String term

Unfortunately this will not be recognized by the servlet.

There are ways to bind the URI, e.g.
@RequestMapping("**/catalogue") and also @RequestMapping("{language}/{country}/catalogue") will work, but with a third path variable the it stops working.

The controller itself is also mapped to a specific path.

Is there a limit for path variables? Is it possible that other wildcards (e.g. @RequestMapping("**")) will be higher evaluated? e.g. 2 wildcards more specific than 3 defined values. But wildcards should be the last matching option in praxis.

Regarding the appearing error:
First, with the wildcard mappings, they will be matched. When I disable the wildcard mappings a org.springframework.web.HttpRequestMethodNotSupportedException error is thrown.

15:42:53,881  DEBUG [http-bio-18091-exec-31] (org.springframework.web.servlet.DispatcherServlet) - Handler execution resulted in exception - forwarding to resolved error view: ModelAndView: reference to view with name 'errors/exception'; model is null
org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'GET' not supported
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter$ServletHandlerMethodResolver.resolveHandlerMethod(AnnotationMethodHandlerAdapter.java:665)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:431)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:424)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:900)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:827)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:778)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at [device detection filter]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:936)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:722)

The Controller method:

@RequestMapping(value = "{language}/{country}/{term}/catalogue", method = RequestMethod.GET)
public ModelAndView catalogue(HttpServletRequest request, HttpServletResponse response, @PathVariable("language") String language, @PathVariable("country") String country, @PathVariable("term") String term, @RequestParam(value = "d", defaultValue = "") String device, @RequestParam(value = "embedded", defaultValue = "false") String embedded, @RequestParam(value = "id", defaultValue = "") String idString, @RequestParam(value = "nr", defaultValue = "") String nr) {

As ask, here are all RequestMappings from the controller (Sorry, I can't post the complete code from the controller here):

@Controller
@RequestMapping("xyz/")
public class Controller {

@RequestMapping(value = "{language}/{country}/{term}/catalogue", method = RequestMethod.GET)

@RequestMapping("**")

@RequestMapping("{language}/{country}/product")

@RequestMapping("{language}/{country}/product-detail")

@RequestMapping("{language}/{country}/product-search")

@RequestMapping("{language}/{country}/dealer-search")

@RequestMapping("{language}/{country}/product-finder")

@RequestMapping("{language}/{country}/table")

@RequestMapping("**/languages")

@RequestMapping("**/chooseLanguages")
}    

Thanks for help.

14
  • Please provide more context, i.e. the controller class' @RequestMapping and other methods' @RequestMappings involved. Commented Jan 16, 2015 at 14:08
  • @Controller @RequestMapping("xyz") Commented Jan 16, 2015 at 14:20
  • 2
    What about the error? When does it occur? Are you getting a 404 response from Spring when you send the request or is it that the application didn't manage to start? Commented Jan 16, 2015 at 14:26
  • vote up for the error thats occuring, maybe a stack trace? Commented Jan 16, 2015 at 14:34
  • The Controller annotation is: @Controller @RequestMapping("xyz"). There are also 2 Wildcard methods, one in the root controller and one in the "xyz" controller. Spring version is 3.1.0.RELEASE. Other Mappings with wildcards have a static value at the end (e.g. **/example) Commented Jan 16, 2015 at 14:37

5 Answers 5

8

Try this. Don't forget the ("lang") in the path variable declaration in your method parameter

@RequestMapping(value = "/{lang}/{count}/{term}", method=RequestMethod.GET)
public ResponseEntity<?> getSomething(@PathVariable("lang") String lang, @PathVariable("count") String count, @PathVariable("term") String term) {
Sign up to request clarification or add additional context in comments.

1 Comment

Can you explain why this is a good idea, and what the relevant difference is with what the OP is already doing? Are you saying that "language" is somehow not a good name for a path variable?
1

This may be a bug (fixed in Spring 4.1): check out SPR-6741.

As described in the issue, you have in the same controller:

  • a mapping with 3 path variables
  • a "fallback" mapping /**

Comments

1

First of all, you're missing a / (slash) at the end of xyz in the controller's @RequestMapping (or a / at the beggining of every method's @RequestMapping). This is the main reason for your 3 path variable method being never invoked.

@RequestMapping(value = "{language}/{country}/{term}/catalogue", method = RequestMethod.GET)

However, once you solve that, I think you might have another problem. According to Spring docs (link here):

When a URL matches multiple patterns, a sort is used to find the most specific match.

A pattern with a lower count of URI variables and wild cards is considered more specific.

This means that when you enable wildcard matching, even if you added the / at the end of your controller's @RequestMapping, your 3 path variable method wouldn't be invoked, because the one with wildcards is considered more specific by Spring.

Please check all @RequestMappings for missing slashes. I advise you to always begin with a slash, this way it's easier to distinguish URL mappings in your code.

Comments

0

Just put this in your code it would be work nice :

@GetMapping(value = "{language}/{country}/{term}/catalogue",produces = {"application/json"})
public @ResponseBody String test(@PathVariable String language,@PathVariable String country,@PathVariable String term) {

        return language+"\t"+country+"\t"+term
    }

You'd pass in: http://localhost:8080/api/Français/France/fr/catalogue

Comments

-1

Try this:

@RequestMapping(value = "/{lang}/{count}/{term}", method=RequestMethod.GET)
public ResponseEntity<?> getSomething(@PathVariable("lang") String lang, @PathVariable("count") String count, @PathVariable("term") String term) {
   // Your code goes here.
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.