Spring-MVC Problem using @Controller on controller implementing an interface

layne picture layne · Sep 30, 2008 · Viewed 50.7k times · Source

I'm using spring 2.5 and annotations to configure my spring-mvc web context. Unfortunately, I am unable to get the following to work. I'm not sure if this is a bug (seems like it) or if there is a basic misunderstanding on how the annotations and interface implementation subclassing works.

For example,

@Controller
@RequestMapping("url-mapping-here")
public class Foo {
  @RequestMapping(method=RequestMethod.GET)
  public void showForm() {
    ...
  }
  @RequestMapping(method=RequestMethod.POST)
  public String processForm() {
  ...
  }
}

works fine. When the context starts up, the urls this handler deals with are discovered, and everything works great.

This however does not:

@Controller
@RequestMapping("url-mapping-here")
public class Foo implements Bar {
  @RequestMapping(method=RequestMethod.GET)
  public void showForm() {
    ...
  }
  @RequestMapping(method=RequestMethod.POST)
  public String processForm() {
  ...
  }
}

When I try to pull up the url, I get the following nasty stack trace:

javax.servlet.ServletException: No adapter for handler [com.shaneleopard.web.controller.RegistrationController@e973e3]: Does your handler implement a supported interface like Controller?
    org.springframework.web.servlet.DispatcherServlet.getHandlerAdapter(DispatcherServlet.java:1091)
    org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:874)
    org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:809)
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:571)
    org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:501)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:627)

However, if I change Bar to be an abstract superclass and have Foo extend it, then it works again.

@Controller
@RequestMapping("url-mapping-here")
public class Foo extends Bar {
  @RequestMapping(method=RequestMethod.GET)
  public void showForm() {
    ...
  }
  @RequestMapping(method=RequestMethod.POST)
  public String processForm() {
  ...
  }
}

This seems like a bug. The @Controller annotation should be sufficient to mark this as a controller, and I should be able to implement one or more interfaces in my controller without having to do anything else. Any ideas?

Answer

James Kingsbery picture James Kingsbery · Jul 7, 2010

What I needed to do was replace

 <tx:annotation-driven/>

with

 <tx:annotation-driven  proxy-target-class="true"/>

This forces aspectj to use CGLIB for doing aspects instead of dynamic proxies - CGLIB doesn't lose the annotation since it extends the class, whereas dynamic proxies just expose the implemented interface.