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

Validator.validate method that calls nested class validate() gets wrong object in childs error.entity validation [SPR-13245] #17836

Closed
spring-projects-issues opened this issue Jul 16, 2015 · 3 comments
Labels
in: core status: bulk-closed

Comments

@spring-projects-issues
Copy link
Collaborator

@spring-projects-issues spring-projects-issues commented Jul 16, 2015

Bruce Edge opened SPR-13245 and commented

I'm implementing a Validator for a class with a nested array of children objects and the child validator is failing because the context in which the child validator runs contains the parent's reference in the Error.entity instead of the child's.

I'm following the docs here: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/validation.html

My data model, a parent Collection object with a child Collectionitem list.

public class Collection {
    private String name;
    private List<CollectionItem> items;
}

public class CollectionItem {
   private String title;
}

My Collection parent and CollectionItem child validators:

@Component
public class CollectionValidator implements Validator {

	@Override
	public boolean supports(Class clazz) {
		return Collection.class.equals(clazz);
	}
        // DI for nested object validator
       @Autowired CollectionItemValidator collectionItemValidator;

        @Override
	public void validate(Object obj, Errors errors) {
		ValidationUtils.rejectIfEmpty(errors, "name", "empty", "missing");
		try {
                       errors.pushNestedPath("items");
			for(CollectionItem collectionItem : collection.getItems()) {  // Validate each Collectionitem object
				ValidationUtils.invokeValidator(collectionItemValidator, collectionItem, errors);
			}
		}
		finally {
			errors.popNestedPath();
		}
	}
}

@Component
public class CollectionItemValidator implements Validator {
	@Override
	public boolean supports(Class clazz) {
		return CollectionItem.class.equals(clazz);
	}
	@Override
	public void validate(Object obj, Errors e) {          
               // The Error e.entity here has the wrong (parent) object in it when called from 
               // ValidationUtils.invokeValidator(collectionItemValidator, collectionItem, errors);
               // Therefore "title" is never found, as the parent Collection object does not have a "title" field.
		ValidationUtils.rejectIfEmpty(e, "title", "empty", "missing")
	}
}

The problem is that when the child items array is validated and CollectionItemValidator.validate() is called for each ColectionItem by ValidationUtils.invokeValidator(collectionItemValidator...) , the Error e.entity passed into the child validator is a still the parent Collection, not the child CollectionItem object, so the check for a "title" field always fails because ValidationUtils.rejectIfEmpty is looking at the parent rather than the child object in the errors.getFieldValue(field);:

	public static void rejectIfEmpty(
			Errors errors, String field, String errorCode, Object[] errorArgs, String defaultMessage) {
		Object value = errors.getFieldValue(field);
....

is using the parent Collection object in the errors.getFieldValue(), so it never finds the field as only the child has a "title" field, the parent does not.

Note that the ValidationUtils

	public static void invokeValidator(Validator validator, Object obj, Errors errors, Object... validationHints) {

has the right obj in the args, the problem is that the errors.entity is never updated to point to the child element.


Affects: 4.2 RC2

1 votes, 2 watchers

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Jul 16, 2015

Bruce Edge commented

This actually using org.springframework:spring-core:4.2.0.BUILD-SNAPSHOT

I added a

System.out.println("Parent:" + errors.getObjectName());

to the Collection validator and a

System.out.println("Child:" + errors.getObjectName());

to the child CollectionItem validator.

Logs show:

2015-07-16 16:01:26.454 DEBUG 46273 --- [nio-9100-exec-2] o.s.validation.ValidationUtils           : Invoking validator [com.nim.collections.CollectionItemValidator@446f7efb]
Parent:Collection
2015-07-16 16:23:09.850 DEBUG 46273 --- [nio-9100-exec-2] o.s.validation.ValidationUtils           : Invoking validator [com.nim.collections.CollectionItemValidator@446f7efb]
Child:Collection

ie: the child's error.entity is still a collection and not a collectionItem

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Aug 30, 2015

Adi commented

The issue is how you're invoking the CollectionItemValidator for each item.
Here you just push the current path without any index, instead what you should do is push it with an index value, like:

int i = 0;
for(CollectionItem collectionItem : collection.getItems()) {  // Validate each Collectionitem object
   try {
       errors.pushNestedPath("items["+ i++ +"]");
       ValidationUtils.invokeValidator(collectionItemValidator, collectionItem, errors);
   } finally { 
       errors.popNestedPath(); 
   }
}

The ValidationUtils always has the parent object's reference, and it needs the complete path of the child object you're referring to. The nested object which you're passing as an argument during invokeValidator is only for your reference or your custom validations. If you're going to use ValidationUtils methods to validate, then you need to specify the complete path as it is going to lookup the field value from the parent object.

@spring-projects-issues spring-projects-issues added type: bug status: waiting-for-triage in: core and removed type: bug labels Jan 11, 2019
@rstoyanchev rstoyanchev added status: bulk-closed and removed status: waiting-for-triage labels Jan 11, 2019
@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Jan 12, 2019

Bulk closing outdated, unresolved issues. Please, reopen if still relevant.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: core status: bulk-closed
Projects
None yet
Development

No branches or pull requests

2 participants