Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 227
Ayub Malik Avatar asked Jun 26 '13 22:06

Ayub Malik


2 Answers

If anybody ever wants to prioritize custom handlers over default handlers added by spring, here's a snippet that does it for me, I do this in a @Configuration file

private @Inject RequestMappingHandlerAdapter adapter;

@PostConstruct
public void prioritizeCustomArgumentMethodHandlers () {
  List<HandlerMethodArgumentResolver> argumentResolvers = 
      new ArrayList<> (adapter.getArgumentResolvers ());
  List<HandlerMethodArgumentResolver> customResolvers = 
      adapter.getCustomArgumentResolvers ();
  argumentResolvers.removeAll (customResolvers);
  argumentResolvers.addAll (0, customResolvers);
  adapter.setArgumentResolvers (argumentResolvers);
}
like image 97
Lev Kuznetsov Avatar answered Sep 21 '22 05:09

Lev Kuznetsov


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!

like image 34
Ayub Malik Avatar answered Sep 23 '22 05:09

Ayub Malik