Wednesday, September 28, 2011

ControllerClassnameHandlerMapping in Spring

ControllerClassnameHandlerMapping is a very good way when it comes to cleaning up spring xml configurations and as I see it enforcing a sort of convention within your application of building URLs. Detailed documentation can be found here so i'll skip that part and summarize it before I go to other things. Provided you stick to a naming convention with your Controllers, Views it enables creating clean URLs with a sort of uniform access for your application, reduces the amount of code you write. Which is to say that a URL /project will be mapped to ProjectController, and not just that if you've added a POJO bean called project in the Model you return, you don't need to name to view or the attribute you are adding before you forward or redirect to it.

But there are some lesser know things about using which got me stuck before I could fully utilize this feature and hence this blog post aims at elaborating those parts (it is based on all I learned trying to solve issues in my application and doing those long searches in Spring Forums.); it can be my bad Google skills though but I have always been a refer documentation and forums person than search. I start listing it out now:

You will have to set the property default handler when configuring it as a bean in your spring XML if you are using SimpleControllerHandlerAdapter, not specifying a default handler in such a case gives the following exception:

javax.servlet.ServletException: No adapter for handler [your.controller.ProjectController@6d78ddf4]: 
Does your handler implement a supported interface like Controller?
	org.springframework.web.servlet.DispatcherServlet.getHandlerAdapter(DispatcherServlet.java:967)
	org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:760)
	org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719)
	org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644)
	org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:549)
here's how you do that
<!-- Bind to a naming convention for controllers and views -->
  <beans:bean id="classnameControllerMappings"
    class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"
    <beans:property name="defaultHandler">
      <beans:bean
        class="org.springframework.web.servlet.mvc.UrlFilenameViewController" />
    </beans:property>
  </beans:bean>

There is another approach; which lets you through without having to tweak too much in the configuration: use AnnotationMethodHandlerAdapter and annotate the methods to be invoked for a URI through the

@RequestMapping
annotations, your bean definitions then look like as follows

  <!-- Bind to a naming convention for controllers and views -->
  <beans:bean id="classnameControllerMappings" 
class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping">
  </beans:bean>

  <!-- Enables annotated POJO @Controllers -->
  <beans:bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
Paths mapped by this approach
ProjectController --> /project /project/*
which means a URL like
/project/create
will be mapped, but a
/project/details/show
won't. So you have to ensure your URLs do not have a third path element. That won't work with this approach and is not a part of this mapping class specification.

No comments: