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 method2And 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=[]}]
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With