Uploaded image for project: 'Spring Framework'
  1. Spring Framework
  2. SPR-15916

Error on type argument constraint validation failure

    Details

    • Last commented by a User:
      false

      Description

      When using type argument constraints on a collection, if a validation failure occurs, a NotReadablePropertyException is thrown.

      The issues occurs with Spring 4.3.10 and Hibernate 5.3.5, but not with Spring 4.3.9 and Hibernate 5.2.5.

      First noticed this when upgrading from Spring Boot 1.4.7 to 1.5.6.

      A minimal reproduction is available at https://github.com/mdjnewman/spring-framework-issues/tree/master/SPR-15916.

      The following error is thrown by shouldRaise400IfNestedValidationFails in the demo project:

      org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.IllegalStateException: JSR-303 validated property 'thingIds[0].<collection element>' does not have a corresponding accessor for Spring data binding - check your DataBinder's configuration (bean property versus direct field access)
       
      	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:982)
      	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
      	at javax.servlet.http.HttpServlet.service(HttpServlet.java:687)
      	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
      	at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:65)
      	at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
      	at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:167)
      	at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:134)
      	at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:155)
      	at org.springframework.issues.TestControllerTests.doTheThingShouldNotDoTheThingWithoutAnId(TestControllerTests.java:56)
      	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
      	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      	at java.lang.reflect.Method.invoke(Method.java:498)
      	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
      	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
      	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
      	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
      	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
      	at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
      	at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
      	at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
      	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
      	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
      	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
      	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
      	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
      	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
      	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
      	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
      	at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
      	at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
      	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
      	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
      	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
      	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
      	at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:51)
      	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
      	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
      Caused by: java.lang.IllegalStateException: JSR-303 validated property 'thingIds[0].<collection element>' does not have a corresponding accessor for Spring data binding - check your DataBinder's configuration (bean property versus direct field access)
      	at org.springframework.validation.beanvalidation.SpringValidatorAdapter.processConstraintViolations(SpringValidatorAdapter.java:162)
      	at org.springframework.validation.beanvalidation.SpringValidatorAdapter.validate(SpringValidatorAdapter.java:117)
      	at org.springframework.validation.DataBinder.validate(DataBinder.java:891)
      	at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.validateIfApplicable(ModelAttributeMethodProcessor.java:168)
      	at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.resolveArgument(ModelAttributeMethodProcessor.java:115)
      	at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121)
      	at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:158)
      	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:128)
      	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97)
      	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)
      	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)
      	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
      	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967)
      	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901)
      	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
      	... 38 more
      Caused by: org.springframework.beans.NotReadablePropertyException: Invalid property 'thingIds[0].<collection element>' of bean class [org.springframework.issues.model.ThingRequest]: Bean property 'thingIds[0].<collection element>' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?
      	at org.springframework.beans.AbstractNestablePropertyAccessor.getPropertyValue(AbstractNestablePropertyAccessor.java:633)
      	at org.springframework.beans.AbstractNestablePropertyAccessor.getPropertyValue(AbstractNestablePropertyAccessor.java:624)
      	at org.springframework.validation.AbstractPropertyBindingResult.getActualFieldValue(AbstractPropertyBindingResult.java:99)
      	at org.springframework.validation.AbstractBindingResult.getRawFieldValue(AbstractBindingResult.java:283)
      	at org.springframework.validation.beanvalidation.SpringValidatorAdapter.getRejectedValue(SpringValidatorAdapter.java:268)
      	at org.springframework.validation.beanvalidation.SpringValidatorAdapter.processConstraintViolations(SpringValidatorAdapter.java:148)
      	... 52 more
      

        Issue Links

          Activity

          Hide
          mdjnewman Matt Newman added a comment -

          On further inspection, 4.3.10 works with Hibernate 5.2.5 ... maybe this is a Hibernate issue?

          Show
          mdjnewman Matt Newman added a comment - On further inspection, 4.3.10 works with Hibernate 5.2.5 ... maybe this is a Hibernate issue?
          Hide
          juergen.hoeller Juergen Hoeller added a comment -

          This looks like you're using Hibernate Validator 6.0 there... Could you check the specific version? (since "Hibernate" itself is ambigous between ORM and Validator)

          We generally only have Bean Validation 2.0 and Hibernate Validator 6.0 support in Spring Framework 5.0. That said, we could add some tolerance to 4.3.11 as well.

          Show
          juergen.hoeller Juergen Hoeller added a comment - This looks like you're using Hibernate Validator 6.0 there... Could you check the specific version? (since "Hibernate" itself is ambigous between ORM and Validator) We generally only have Bean Validation 2.0 and Hibernate Validator 6.0 support in Spring Framework 5.0. That said, we could add some tolerance to 4.3.11 as well.
          Hide
          cinphart Peter Hart added a comment - - edited

          I'm a colleague of Matt's looking at this issue also. This issue is definitely occurring with hibernate validator > 5.2.5 < 6.0. It also looks like the fix that has been used for validation 2.0 won't work for hibernate 5.3, as the path returned by hibernate in this case is subtly different from the one returned by hibernate 6.0/validation 2.0. The path being looked at in SpringValidatorAdapter::determineField is thingIds[0].<collection element>, whereas for 2.0 validation, if I'm understanding this correctly, it should be defined as thingIds[0].<list element>. Also, in hibernate 6.0, it looks like the final node in the path has kind 'CONTAINER_ELEMENT', whereas with hibernate 5.3 it's seems to have type PROPERTY, because validator 1.1 doesn't have/support the CONTAINER_ELEMENT kind.

          Show
          cinphart Peter Hart added a comment - - edited I'm a colleague of Matt's looking at this issue also. This issue is definitely occurring with hibernate validator > 5.2.5 < 6.0. It also looks like the fix that has been used for validation 2.0 won't work for hibernate 5.3, as the path returned by hibernate in this case is subtly different from the one returned by hibernate 6.0/validation 2.0. The path being looked at in SpringValidatorAdapter::determineField is thingIds [0] .<collection element>, whereas for 2.0 validation, if I'm understanding this correctly, it should be defined as thingIds [0] .<list element>. Also, in hibernate 6.0, it looks like the final node in the path has kind 'CONTAINER_ELEMENT', whereas with hibernate 5.3 it's seems to have type PROPERTY, because validator 1.1 doesn't have/support the CONTAINER_ELEMENT kind.
          Hide
          juergen.hoeller Juergen Hoeller added a comment -

          Thanks for the insight. I guess we'll have to do some lenient sanity processing of the path, truncating any part starting with a "<" here. We'll also apply that to our 5.0 branch since it is still supposed to be compatible with Hibernate Validator 5.x as well.

          Show
          juergen.hoeller Juergen Hoeller added a comment - Thanks for the insight. I guess we'll have to do some lenient sanity processing of the path, truncating any part starting with a "<" here. We'll also apply that to our 5.0 branch since it is still supposed to be compatible with Hibernate Validator 5.x as well.
          Hide
          juergen.hoeller Juergen Hoeller added a comment -

          I've revised the algorithm to ignore path elements starting with "<" in addition to selecting them by element kind 'property', making it compatible with Bean Validation 2.0 / Hibernate Validator 6.0 as well as HV5's variant of the feature there. This is available in master for 5.0 RC4 now, along with our general Bean Validation 2.0 story.

          For 4.3.11, I'll backport a variant that ignores a path as of the "<" part at least. This is just a Hibernate Validator specific feature outside of a fully supported Bean Validation generation there, but we should nevertheless be able to leniently handle it... tolerating HV5 as well as HV6's variant if we happen to encounter it at runtime.

          Show
          juergen.hoeller Juergen Hoeller added a comment - I've revised the algorithm to ignore path elements starting with "<" in addition to selecting them by element kind 'property', making it compatible with Bean Validation 2.0 / Hibernate Validator 6.0 as well as HV5's variant of the feature there. This is available in master for 5.0 RC4 now, along with our general Bean Validation 2.0 story. For 4.3.11, I'll backport a variant that ignores a path as of the "<" part at least. This is just a Hibernate Validator specific feature outside of a fully supported Bean Validation generation there, but we should nevertheless be able to leniently handle it... tolerating HV5 as well as HV6's variant if we happen to encounter it at runtime.

            People

            • Assignee:
              juergen.hoeller Juergen Hoeller
              Reporter:
              mdjnewman Matt Newman
              Last updater:
              St├ęphane Nicoll
            • Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:
                Days since last comment:
                3 weeks, 1 day ago