Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring MVC picks the wrong controller method

In my application I have a situation where spring mvc consistently picks the wrong controller method to execute. the debug log from spring below shows the problem, it finds two matches one for my general purpose handle all unhanded mappings controller which is mapped to /api/** and one for the actual thing I am looking for api/companies/2/records/cabinets/FileTypes/50/1 spring mvc then picks /api/** handler over the more specific handler that it found.

My understanding of spring is that if there are two matches for a request mapping, then spring will pick the handle method with a longer url. Why is spring mvc picking the shorter mapping?

Given the following mappings:

  • /api/companies/{id}/records/cabinets/FileTypes/{fileTypeId}/{versionId} mapped to method1
  • /api/** mapped to method2

And the path api/companies/2/records/cabinets/FileTypes/50/1 what should spring mvc pick as the handler method for the two above url.

here are the relevant lines form the debug log.

17:58:49,858 DEBUG [DispatcherServlet] DispatcherServlet with name 'main' processing PUT request for [/web/api/companies/2/records/cabinets/FileTypes/50/1]
17:58:49,858 TRACE [DispatcherServlet] Testing handler map [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping@2b25f2be] in DispatcherServlet with name 'main'
7:58:49,858 DEBUG [RequestMappingHandlerMapping] Looking up handler method for path /api/companies/2/records/cabinets/FileTypes/50/1
17:58:49,859 TRACE [RequestMappingHandlerMapping] Found 2 matching mapping(s) for [/api/companies/2/records/cabinets/FileTypes/50/1] : [{[/api/**],methods=[PUT],params=[],headers=[],consumes=[],produces=[],custom=[]}, {[/api/companies/{id}/records/cabinets/FileTypes/{fileTypeId}/{versionId}],methods=[PUT],params=[],headers=[],consumes=[],produces=[],custom=[]}]
like image 605
ams Avatar asked May 20 '13 22:05

ams


2 Answers

This indeed is a bug (see here and here).

I believe the mapping takes into account the number of brackets in the first expression:

/api/companies/{id}/records/cabinets/FileTypes/{fileTypeId}/{versionId}
               ^--                             ^--          ^--

As there are three brackets (patterns) in the first, and only one pattern (**) in the second, the first is considered more general.

Workaround:

As * and /* evaluates in the same way, try making the second expression, instead of /api/**, like:

/api/**/**/**/**

This has four patterns, thus making it "more general" than the other one. In practice, though, it is equivalent to /api/**. This will make it evaluate lastly.

As this somewhat "easy" workaround exists, I believe the bug will take long to be corrected, if it ever will.

like image 149
acdcjunior Avatar answered Oct 21 '22 00:10

acdcjunior


I am able to replicate the behavior you are seeing. So your behavior is with two mappings:

. /api/companies/{id}/records/cabinets/FileTypes/{fileTypeId}/{versionId}

. /api/**

a request to /api/companies/2/records/cabinets/FileTypes/50/1 matches the second path.

I tried a little different path:

. /api/companies/{id}/records/cabinets/FileTypes

. /api/**

with a request to /api/companies/2/records/cabinets/FileTypes , this time around the first one matches up!

I think this is a bug, I would recommend filing a ticket at the Spring JIRA site.

like image 3
Biju Kunjummen Avatar answered Oct 21 '22 01:10

Biju Kunjummen