Search code examples
springspring-mvcannotations

Spring HandlerMethodArgumentResolver not executing


I am using Spring MVC 3.2.2

I have defined a custom HandlerMethodArgumentResolver class like this

public class CurrentUserArgumentResolver implements HandlerMethodArgumentResolver {

  public CurrentUserArgumentResolver() {
    System.out.println("Ready");
  }

  @Override
  public boolean supportsParameter(MethodParameter parameter) {
    return parameter.hasParameterAnnotation(CurrentUser.class);
  }

  @Override
  public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
        NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {

      Principal principal = webRequest.getUserPrincipal();
      System.out.println("*** Principal ***: " + principal);
      return principal;
  }
}

And added the following to my app-servlet.xml

<mvc:annotation-driven>
  <mvc:argument-resolvers>
    <beans:bean class="my.package.CurrentUserArgumentResolver" lazy-init="false"/>
  </mvc:argument-resolvers>
</mvc:annotation-driven>

and created an annotation for CurrentUser

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface CurrentUser {

}

When I start the application up the class is constructed as I can see the log message "Ready" but the resolver does not execute when I annotate a controller method as such (in a class that has @Controller annotation)

@RequestMapping(method = RequestMethod.POST, value = "/update")
public ModelAndView update(@RequestParam MultipartFile background, @CurrentUser Principal principal) {
 ...
}

If I put breakpoints on either method in the CurrentUserArgumentResolver class, neither work. So not sure what I am missing?


Solution

  • OK I worked out that Spring was already resolving the Principal object in my above example and so my argument resolver was not kicking in. I had been lazy and added the @CurrentUser annotation to an existing parameter.

    So I changed my example

    @RequestMapping(method = RequestMethod.POST, value = "/update")
    public ModelAndView update(@RequestParam MultipartFile background, @CurrentUser Principal principal) {
      ...
    }
    

    to use my User model class

    @RequestMapping(method = RequestMethod.POST, value = "/update")
    public ModelAndView update(@RequestParam MultipartFile background, @CurrentUser User user) {
      ...
    }
    

    and now it works!