Skip to content

ProxyingHandlerMethodArgumentResolver handles interfaces not intended for projection [DATACMNS-776] #1237

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
spring-projects-issues opened this issue Oct 13, 2015 · 4 comments
Assignees
Labels
type: bug A general bug
Milestone

Comments

@spring-projects-issues
Copy link

Andy Wilkinson opened DATACMNS-776 and commented

A Spring Boot application that depends on spring-boot-starter-data-pa and uses Spring Mobile will create a proxy for Spring Mobile's Device interface when it's injected into a handler method. Calling isMobile on this proxy fails as follows:

org.springframework.aop.AopInvocationException: Null return value from advice does not match primitive return type for: public abstract boolean org.springframework.mobile.device.Device.isMobile()
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:220) ~[spring-aop-4.2.2.BUILD-SNAPSHOT.jar:4.2.2.BUILD-SNAPSHOT]
	at com.sun.proxy.$Proxy64.isMobile(Unknown Source) ~[na:na]
	at com.example.controllers.IndexController.getIndex(IndexController.java:17) ~[classes/:na]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_60]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_60]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_60]
	at java.lang.reflect.Method.invoke(Method.java:497) ~[na:1.8.0_60]
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221) ~[spring-web-4.2.2.BUILD-SNAPSHOT.jar:4.2.2.BUILD-SNAPSHOT]
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137) ~[spring-web-4.2.2.BUILD-SNAPSHOT.jar:4.2.2.BUILD-SNAPSHOT]
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110) ~[spring-webmvc-4.2.2.BUILD-SNAPSHOT.jar:4.2.2.BUILD-SNAPSHOT]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:806) ~[spring-webmvc-4.2.2.BUILD-SNAPSHOT.jar:4.2.2.BUILD-SNAPSHOT]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:729) ~[spring-webmvc-4.2.2.BUILD-SNAPSHOT.jar:4.2.2.BUILD-SNAPSHOT]
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) ~[spring-webmvc-4.2.2.BUILD-SNAPSHOT.jar:4.2.2.BUILD-SNAPSHOT]
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959) ~[spring-webmvc-4.2.2.BUILD-SNAPSHOT.jar:4.2.2.BUILD-SNAPSHOT]
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893) ~[spring-webmvc-4.2.2.BUILD-SNAPSHOT.jar:4.2.2.BUILD-SNAPSHOT]
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) ~[spring-webmvc-4.2.2.BUILD-SNAPSHOT.jar:4.2.2.BUILD-SNAPSHOT]
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861) ~[spring-webmvc-4.2.2.BUILD-SNAPSHOT.jar:4.2.2.BUILD-SNAPSHOT]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:622) ~[tomcat-embed-core-8.0.28.jar:8.0.28]
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) ~[spring-webmvc-4.2.2.BUILD-SNAPSHOT.jar:4.2.2.BUILD-SNAPSHOT]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:729) ~[tomcat-embed-core-8.0.28.jar:8.0.28]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291) ~[tomcat-embed-core-8.0.28.jar:8.0.28]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) ~[tomcat-embed-core-8.0.28.jar:8.0.28]
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) ~[tomcat-embed-websocket-8.0.28.jar:8.0.28]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) ~[tomcat-embed-core-8.0.28.jar:8.0.28]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) ~[tomcat-embed-core-8.0.28.jar:8.0.28]
	at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:87) ~[spring-web-4.2.2.BUILD-SNAPSHOT.jar:4.2.2.BUILD-SNAPSHOT]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.2.2.BUILD-SNAPSHOT.jar:4.2.2.BUILD-SNAPSHOT]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) ~[tomcat-embed-core-8.0.28.jar:8.0.28]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) ~[tomcat-embed-core-8.0.28.jar:8.0.28]
	at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77) ~[spring-web-4.2.2.BUILD-SNAPSHOT.jar:4.2.2.BUILD-SNAPSHOT]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.2.2.BUILD-SNAPSHOT.jar:4.2.2.BUILD-SNAPSHOT]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) ~[tomcat-embed-core-8.0.28.jar:8.0.28]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) ~[tomcat-embed-core-8.0.28.jar:8.0.28]
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:85) ~[spring-web-4.2.2.BUILD-SNAPSHOT.jar:4.2.2.BUILD-SNAPSHOT]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.2.2.BUILD-SNAPSHOT.jar:4.2.2.BUILD-SNAPSHOT]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) ~[tomcat-embed-core-8.0.28.jar:8.0.28]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) ~[tomcat-embed-core-8.0.28.jar:8.0.28]
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:217) ~[tomcat-embed-core-8.0.28.jar:8.0.28]
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106) [tomcat-embed-core-8.0.28.jar:8.0.28]
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502) [tomcat-embed-core-8.0.28.jar:8.0.28]
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142) [tomcat-embed-core-8.0.28.jar:8.0.28]
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) [tomcat-embed-core-8.0.28.jar:8.0.28]
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88) [tomcat-embed-core-8.0.28.jar:8.0.28]
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518) [tomcat-embed-core-8.0.28.jar:8.0.28]
	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091) [tomcat-embed-core-8.0.28.jar:8.0.28]
	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:673) [tomcat-embed-core-8.0.28.jar:8.0.28]
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1500) [tomcat-embed-core-8.0.28.jar:8.0.28]
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1456) [tomcat-embed-core-8.0.28.jar:8.0.28]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_60]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_60]
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.0.28.jar:8.0.28]
	at java.lang.Thread.run(Thread.java:745) [na:1.8.0_60]

The culprit is ProxyingHandlerMethodArgumentResolver which takes responsibility for any argument that's an interface. I can work around the problem by ensuring that Spring Mobile's DeviceHandlerMethodArgumentResolver appears before ProxyingHandlerMethodArgumentResolver in Spring MVC's list of argument resolvers but I'd prefer not to have to do so. Can ProxyingHandlerMethodArgumentResolver be fixed so that it either doesn't claim responsibility for anything that's an interface, or so that it returns a working proxy?


Affects: 1.10.2 (Fowler SR2), 1.11 GA (Gosling)

Issue Links:

  • DATACMNS-954 Pageable resolver breaks annotation WithUserDetails
    ("is duplicated by")

Backported to: 1.13 GA (Ingalls), 1.12.7 (Hopper SR7), 1.11.7 (Gosling SR7)

4 votes, 8 watchers

@spring-projects-issues
Copy link
Author

Dmitry Roenko commented

Yesterday I've stumbled upon this issue. Here's minimal example to trigger this bug

@SpringBootApplication
@Controller
public class TestApplication {
  @RequestMapping(path = "/bug",method = RequestMethod.POST)
  public String test(List<String> entities) {
    try {
      entities.size();
    } catch (Exception e) {
      e.printStackTrace();
    }
    return "i'm fine";
  }

  public static void main(String[] args) {
    SpringApplication.run(TestApplication.class, args);
  }
}

The code above will throw an java.lang.IllegalArgumentException: Invoked method public abstract int java.util.List.size() is no accessor method! exception, in response for curl -i -X POST -d 'a' http://localhost:8080/bug to it.

@spring-projects-issues
Copy link
Author

Marc Vanbrabant commented

We are hitting this issue too when upgrading to Athens platform bom, but not only with Spring Mobile.

Actually this also conflicts with any custom HandlerMethodArgumentResolver. We had to revert to the Impl type in the @RequestMapping as a workaround.

Could this be looked at?

@spring-projects-issues
Copy link
Author

Vedran Pavic commented

This also happens in a Boot based app with Spring Security's @AuthenticationPrincipal annotated UserDetails
argument and CsrfToken argument.

Sample project to reproduce the issue is available here.

IMO this one should have a priority higher than minor

@spring-projects-issues
Copy link
Author

Oliver Drotbohm commented

This should be fixed now. We now back off interfaces from the org.springframework and java namespace unless they're annotated with @ProjectedPayload. Prefer the latter on projection interfaces going forward as that special type inspection might be removed in 2.0 again. It was just the least invasive option for a fix that could still make it into bugfix releases

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug A general bug
Projects
None yet
Development

No branches or pull requests

2 participants