Mixing WebControllers in Spring

Spring 2.5 introduced @Controllers, these are essentially trigger by adding the <context:component-scan base-package="com...." /> item.

This works fine for Annotated Controllers only. However if you are attempting to mix this with existing controllers (say the BeanNameUrlHandlerMapping) you need to add some more explicit definition.

The DefaultAnnotationHandlerMapping states:

NOTE: If you define custom HandlerMapping beans in your
DispatcherServlet context, you need to add a DefaultAnnotationHandlerMapping bean
explicitly, since custom HandlerMapping beans replace the default mapping strategies.


What this means is you should define:

<!-- Note (Spring 2.5): to resolve useage of annotated controllers with bean mapped controllers need to
be explicit with HandlerAdaptors and Handler mappings This is not clear in the documentation
and has been worked out by debugging the spring source --!>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />


I also ran into a further problem where I had an HttpInvokerServiceExporter and that had stopped working (404 error). This was overcome by adding in a SimpleUrlHandlerMapping and HttpRequestHandlerAdapter.


<!-- Note (Spring 2.5): to resolve useage of annotated controllers with bean mapped controllers need to
be explicit with HandlerAdaptors and Handler mappings. This is not clear in the documentation
and has been worked out by debugging the spring source -->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />

<!-- HttpInvoker Support -->
<bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter" />*
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">*
<property name="alwaysUseFullPath" value="true" />
<property name="mappings">
<props>
<prop key="/services/ABCService">nmlServiceExporter</prop>
</props>
</property>
</bean>

Again this was not initially needed when i was running with just an httpinvoker service, since:

<bean name="/ABCService" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
<property name="service" ref="nmlSynchronousService"/>
<property name="serviceInterface" value="com.abc.ABCSynchronousService"/>
</bean>

combined with the web.xml

<servlet>
<servlet-name>abc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>abc</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>

Had previously worked, but once you started combining with other handlers and adapters you need to be explicit with your bean config.

Previous to this I had tried to adjust the web.xml to use a more direct handler servlet:

<servlet>
<servlet-name>remoting</servlet-name>
<servlet-class>
org.springframework.web.context.support.HttpRequestHandlerServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>remoting</servlet-name>
<url-pattern>/proxy</url-pattern>
</servlet-mapping>

But this resulted in the following error:

2009-02-05 19:40:02,040 INFO [org.apache.catalina.core.ContainerBase.[jboss.web].[localhost].[/nml]] Marking servlet nmlExporter as unavailable
2009-02-05 19:40:02,061 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[localhost].[/nml]] Error loading WebappClassLoader^M
delegate: false
repositories:
/WEB-INF/classes/
----------> Parent Classloader:
java.net.FactoryURLClassLoader@53b2c
org.springframework.web.context.org.springframework.web.context.support.HttpRequestHandlerServlet
java.lang.ClassNotFoundException: org.springframework.web.context.org.springframework.web.context.support.HttpRequestHandlerServlet
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1332)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1181)
at org.apache.catalina.core.StandardWrapper$1.run(StandardWrapper.java:1010)
at java.security.AccessController.doPrivileged(Native Method)
at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1006)


Handy Debug Points



org.springframework.web.servlet.DispatcherServlet

  • inside the getHandlerAdapter method
  • inside the initHandlerMappings method
  • (inside the doDispatch method, look around the line: HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()))

Comments