12

I recently upgraded to spring 3.2 and noticed that AnnotationMethodHandlerAdapter had been deprecated in favor of RequestMappingHandlerAdapter. So I reconfigured to use the new class, complete with a custom MessageConverter I need. All fine and good.

However, when attempting to hit a URL supported by an annotated Controller, I'm getting an error:

 [java] javax.servlet.ServletException: No adapter for handler [my.company.TagController@1c2e7808]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler
 [java]     at org.springframework.web.servlet.DispatcherServlet.getHandlerAdapter(DispatcherServlet.java:1128)
 [java]     at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:903)
 [java]     at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)

When debugging the dispatcher, and in particular, the Dispatcher.getHandlerAdapter() method, it's finding my HandlerAdapter, but the AbstractHandlerMethodAdapter.supports() that is invoked wants a MethodHandler:

public final boolean supports(Object handler) {
  return handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler);
}

and the controller is not a HandlerMethod. The AnnotatedMethodHandlerAdapter's support method is.. well, different (and works still!)

public boolean supports(Object handler) {
  return getMethodResolver(handler).hasHandlerMethods();
}

So I apparently cannot simply upgrade to the new class... I'm missing some additional configuration, but the documentation isn't really helping me out. Any ideas?

Thanks.

lunr
  • 5,159
  • 4
  • 31
  • 47
ticktock
  • 1,593
  • 3
  • 16
  • 38

3 Answers3

21

Use "<mvc:annotation-driven/>" in the spring configuration file instead of writing your own implementation of WebMvcConfigurationSupport

example

    <mvc:annotation-driven/>
<context:component-scan base-package="com.springapp.mvc"/>
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
        <property name="messageConverters">
            <list>
                <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
                <bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/>
                <bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter"/>
                <bean class="org.springframework.http.converter.FormHttpMessageConverter"/>
                <bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
            </list>
        </property>

    </bean>
Abhay Phougat
  • 280
  • 2
  • 6
8

So as it turns out, simple switching the bean definition doesn't work due to the fact that the RequestMappingHandlerAdapter is depending on a whole host of entities being created and configured. Spring, by default, is using a WebMvcConfigurationSupport entity to do all this default configuration, but simply creating my own bean version doesn't help because spring creates its own.

My approach ended up being something along the lines of below, where I left basically all of the configuration up to spring's default, but then added my own converter. The only drawback is that it's switching xml configuration to javaconfig, but in my case, it's ok. There's an article here that describes something similar.

@Configuration
public class WebConfig extends WebMvcConfigurationSupport {

  @Bean
  public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
    RequestMappingHandlerAdapter handlerAdapter = super.requestMappingHandlerAdapter();
    handlerAdapter.getMessageConverters().add(0, getProtobufJsonMessageConverter());
    return handlerAdapter;
  }
ticktock
  • 1,593
  • 3
  • 16
  • 38
  • 5
    For what it's worth this was documented http://docs.spring.io/spring-framework/docs/3.1.x/spring-framework-reference/html/new-in-3.1.html#new-in-3.1-handler-method-controller-processing – Rossen Stoyanchev Apr 24 '14 at 12:46
2
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
@Configuration
public class WebConfig extends WebMvcConfigurationSupport {
  @Override
  protected RequestMappingHandlerAdapter createRequestMappingHandlerAdapter() {
    return new XXXXRequestMappingHandlerAdapter();
  }
}