I perform refactoring and split controller into 2 controllers with:
@RequestMapping(value = "/graph.htm", method = RequestMethod.POST, params="first")
in first controller and:
@RequestMapping(value = "/graph.htm", method = RequestMethod.POST, params="second")
in second controller so these annotations lie in different files. When I build and use project all is fine (I put input HTML tag in my forms with different names: first and second).
But when I try to run JUnit controller test:
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = { "classpath:test-context.xml" })
I get trace:
Caused by: java.lang.IllegalStateException: Cannot map handler 'firstController' to URL path [/graph.htm]: There is already handler of type [class com.web.controller.SecondController] mapped. at org.springframework.web.servlet.handler.AbstractUrlHandlerMapping.registerHandler(AbstractUrlHandlerMapping.java:294) at org.springframework.web.servlet.handler.AbstractUrlHandlerMapping.registerHandler(AbstractUrlHandlerMapping.java:266) at org.springframework.web.servlet.handler.AbstractDetectingUrlHandlerMapping.detectHandlers(AbstractDetectingUrlHandlerMapping.java:82) at org.springframework.web.servlet.handler.AbstractDetectingUrlHandlerMapping.initApplicationContext(AbstractDetectingUrlHandlerMapping.java:58) at org.springframework.context.support.ApplicationObjectSupport.initApplicationContext(ApplicationObjectSupport.java:119) at org.springframework.web.context.support.WebApplicationObjectSupport.initApplicationContext(WebApplicationObjectSupport.java:72) at org.springframework.context.support.ApplicationObjectSupport.setApplicationContext(ApplicationObjectSupport.java:73) at org.springframework.context.support.ApplicationContextAwareProcessor.invokeAwareInterfaces(ApplicationContextAwareProcessor.java:117) at org.springframework.context.support.ApplicationContextAwareProcessor.postProcessBeforeInitialization(ApplicationContextAwareProcessor.java:92) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:399) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1479) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:524)
When I comment out this:
@RequestMapping(value = "/graph.htm", method = RequestMethod.POST, params="second")
in second controller individual test for first controller successfully completed.
To resolve this issue I may use different URLs (value in @RequestMapping) but I don't understand why request mapping resolved for params in my production build of application and fail with SpringJUnit4ClassRunner.
Any help welcome!
PS. I use Spring 3.2.
PPS. I found mostly same issue Can I have the same mapping value with different param in a different Spring controller? but according to answers my production build also must fail?! But I run production build successfully!!
Also refer to:
*PPS.
I check official docs for 3.2:
http://static.springsource.org/spring/docs/3.2.x/javadoc-api/org/springframework/web/bind/annotation/RequestMapping.html#params%28%29
In a Servlet environment, parameter mappings are considered as restrictions that are enforced at the type level. The primary path mapping (i.e. the specified URI value) still has to uniquely identify the target handler, with parameter mappings simply expressing preconditions for invoking the handler.
So seems I perform illegal coding practice...
This is what I understand when reading the official doc quoted in your question :
In a Servlet environment, parameter mappings are considered as restrictions that are enforced at the type level. The primary path mapping (i.e. the specified URI value) still has to uniquely identify the target handler within the class, with parameter mappings simply expressing preconditions for invoking the handler.
I added the words "within the class".
And please note the enforced at type level. As I understand, it means that : in a servlet env. declaring the params at method level is quite the same as declaring the params at type level (at least if you only have only one method in your class).
Finally, if you take care to this sentence (same source):
When used at the type level, all method-level mappings inherit this parameter restriction (i.e. the type-level restriction gets checked before the handler method is even resolved).
I think all of this summarize why your are not doing illegal coding.
Regarding unit tests:
What is also important here are the words "In a Servlet environment. Obviously, when running unit tests : your not in a Servlet environment and that's probably why it is failing.
My neighbour colleague help me with debugging issue.
We compare production and test environment and found difference in context XML configuration.
Previous test configuration which fail:
<bean name="handlerMapping" class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/> <bean name="handlerAdapter" class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
New and working test context configuration:
<bean name="handlerMapping" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/> <bean name="handlerAdapter" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
Different spring classes use different mapping schema. Old uses per classes, newer uses per methods!!
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