Skip to content
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

JSR-303 validation doesn't work with nested properties in case of direct field access [SPR-10623] #15251

Closed
spring-projects-issues opened this issue Jun 4, 2013 · 5 comments
Assignees
Labels
in: core Issues in core modules (aop, beans, core, context, expression) type: enhancement A general enhancement
Milestone

Comments

@spring-projects-issues
Copy link
Collaborator

@spring-projects-issues spring-projects-issues commented Jun 4, 2013

Vladimir Kralik opened SPR-10623 and commented

When I use org.springframework.validation.Validator, the IllegalStateException is thrown.

The javax.validation.Validator works correctly.

Look at attached JUnit-test ( also as an maven project in attachement ).

package com.asseco.ce.valid;

import javax.validation.Valid;
import javax.validation.constraints.NotNull;

public class A {   
    @NotNull
    @Valid
    private B b;

    public B getB() {
        return b;
    }
    public void setB(B b) {
        this.b = b;
    }
}
package com.asseco.ce.valid;
import org.hibernate.validator.constraints.NotBlank;

public class B {
    @NotBlank
    private String value;

    public String getValue() {
        return value;
    }
    public void setValue(String value) {
        this.value = value;
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
  <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
 </beans>
package com.asseco.ce.valid;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.validation.DirectFieldBindingResult;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;

import com.asseco.ce.valid.A;
import com.asseco.ce.valid.B;

import static org.junit.Assert.*;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "ValidationIntegrationTest.xml" } )
public class ValidationIntegrationTest {

    @Autowired private Validator springValidator;
    @Autowired private javax.validation.Validator jsr303Validator;
    
    private A a;
    
    @Before
    public void before() {
        a = new A();
        a.setB(new B());
    }
    @Test
    public void jsr303() {
        assertEquals(1, jsr303Validator.validate(a).size());
    }   
    @Test
    public void spring() {
        Errors errors = new DirectFieldBindingResult(a, "A");
        springValidator.validate(a, errors);
        assertEquals(1, errors.getAllErrors().size());
    }
}
java.lang.IllegalStateException: JSR-303 validated property 'b.value' 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:152)
	at org.springframework.validation.beanvalidation.SpringValidatorAdapter.validate(SpringValidatorAdapter.java:89)
	at com.asseco.ce.valid.ValidationIntegrationTest.spring(ValidationIntegrationTest.java:42)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
	at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
	at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
	at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
	at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
	at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: org.springframework.beans.NotReadablePropertyException: Invalid property 'b.value' of bean class [com.asseco.ce.valid.A]: Field 'b.value' does not exist
	at org.springframework.beans.DirectFieldAccessor.getPropertyValue(DirectFieldAccessor.java:106)
	at org.springframework.validation.AbstractPropertyBindingResult.getActualFieldValue(AbstractPropertyBindingResult.java:99)
	at org.springframework.validation.AbstractBindingResult.getRawFieldValue(AbstractBindingResult.java:275)
	at org.springframework.validation.beanvalidation.SpringValidatorAdapter.processConstraintViolations(SpringValidatorAdapter.java:137)
	... 31 more



Affects: 3.2.3

Attachments:

Issue Links:

  • #14339 org.springframework.beans.DirectFieldAccessor fails to go through field paths recursively

Referenced from: commits bc71488

1 votes, 6 watchers

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Jan 2, 2014

Juergen Hoeller commented

This seems to refer to a general limitation with Spring's direct field access: It doesn't come with support for nested properties. We rather 'insist' on accessor methods for such a scenario; we intend to revisit this for 4.1.

For the time being, since you have accessor methods anyway, have you tried regular bean property binding? That should work fine in your scenario.

Juergen

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Jan 20, 2014

Benjamin M commented

+1 !!!

I am waiting for this since decades!

(Mainly because I just want to use public fields within my DTOs)

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Jun 9, 2014

Maciej Walkowiak commented

I submitted a pull request that fixes this issue by adding nested fields traversing feature for DirectFieldAccessor: #543

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Jun 27, 2014

Stéphane Nicoll commented

Work on #14339 fixed this issue. Your test case runs fine with the latest 4.1.0.BUILD-SNAPSHOT

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Jun 2, 2015

chris marx commented

For those of us still on 3.2+, how exactly are we supposed to configure the LocalValidatorFactoryBean such that it does not use direct field access?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: core Issues in core modules (aop, beans, core, context, expression) type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

2 participants