Skip to content

@RequestParam fails when ConfigurableWebBindingInitializer has both messageCodesResolver and conversionService [SPR-7590] #12246

@spring-projects-issues

Description

@spring-projects-issues

Oliver Stacey opened SPR-7590 and commented

I'm seeing an issue that I think is a result of a bug.

I have an AnnotationMethodHandlerAdapter configured thus:

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="webBindingInitializer">
<bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer"
p:messageCodesResolver-ref="messageCodesResolver"
p:conversionService-ref="conversionService" />
</property>
</bean>

I also have a controller method with the following signature:

@RequestMapping(value="/account/name", method = RequestMethod.POST)
public String setName(@RequestParam("name") String name, ModelMap model) {

When this method is invoked, I see a stack trace that looks like:

java.lang.IllegalStateException: Cannot access properties on null bean instance 'name'!
org.springframework.util.Assert.state(Assert.java:384)
org.springframework.validation.BeanPropertyBindingResult.createBeanWrapper(BeanPropertyBindingResult.java:99)
org.springframework.validation.BeanPropertyBindingResult.getPropertyAccessor(BeanPropertyBindingResult.java:87)
org.springframework.validation.AbstractPropertyBindingResult.initConversion(AbstractPropertyBindingResult.java:60)
org.springframework.validation.DataBinder.setConversionService(DataBinder.java:501)
org.springframework.web.bind.support.ConfigurableWebBindingInitializer.initBinder(ConfigurableWebBindingInitializer.java:167)
org.springframework.web.bind.annotation.support.HandlerMethodInvoker.initBinder(HandlerMethodInvoker.java:376)
org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolveRequestParam(HandlerMethodInvoker.java:505)
org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolveHandlerArguments(HandlerMethodInvoker.java:339)
org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:170)
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:421)
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:409)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:774)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644)
org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:560)
javax.servlet.http.HttpServlet.service(HttpServlet.java:647)
javax.servlet.http.HttpServlet.service(HttpServlet.java:729)

What I believe is happening here is as follows:

  • The handler adapter delegates to HandlerMethodInvoker, which attempts to resolve the @RequestParam argument.
  • HandlerMethodInvoker creates a WebRequestDataBinder with a null target.
  • HandlerMethodInvoker then delegates to ConfigurableWebBindingInitializer.initBinder() to initialize the new binder
    • this method in turn calls DataBinder.setMessageCodesResolver(). As a side effect of setting the message code resolver, a BeanPropertyBindingResult is created inside the DataBinder; this also has a null target.
    • then DataBinder.setConversionService() is called, which in turn calls BeanPropertyBindingResult.initConversionService(), which fails with the above exception because the target of the binding result is null.

It seems that the intention here is to support the "null target" case inside WebRequestDataBinder by making sure that bindingResult is never created. However, in this case the binder is accidentally created anyway.

I've attached a patch that overrides setMessageCodesResolver() in WebRequestDataBinder and changes it into a no-op when target is null. This seems like the cleanest simple fix. This should be applied to /trunk/org.springframework.web/src/main/java/org/springframework/web/bind/support/WebRequestDataBinder.java

However, I think there's an inherent contradiction between the approaches taken by DataBinder and WebRequestDataBinder that is likely to generate more bugs in the future. DataBinder seems to be written with the idea that its bindingResult is "lazy loaded"; WebRequestDataBinder supports a case where the bindingResult should never be created. It seems like great care will need to be taken to ensure that no stray calls into DataBinder result in the creation of an unwanted bindingResult.


Affects: 3.0 GA, 3.0.1, 3.0.2, 3.0.3, 3.0.4

Attachments:

Metadata

Metadata

Assignees

Labels

in: coreIssues in core modules (aop, beans, core, context, expression)in: webIssues in web modules (web, webmvc, webflux, websocket)type: bugA general bug

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions