Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
   /*
   * JBoss, Home of Professional Open Source
   * Copyright 2009, Red Hat, Inc. and/or its affiliates, and individual contributors
   * by the @authors tag. See the copyright.txt in the distribution for a
   * full listing of individual contributors.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
  * http://www.apache.org/licenses/LICENSE-2.0
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  package org.hibernate.validator.internal.engine;
  
  import java.util.Arrays;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  
  
  import static org.hibernate.validator.internal.util.CollectionHelper.newArrayList;
  import static org.hibernate.validator.internal.util.CollectionHelper.newHashMap;
  import static org.hibernate.validator.internal.util.logging.Messages.MESSAGES;

The main Bean Validation class. This is the core processing class of Hibernate Validator.

Author(s):
Emmanuel Bernard
Hardy Ferentschik
Gunnar Morling
Kevin Pollet <kevin.pollet@serli.com> (C) 2011 SERLI
  
  public class ValidatorImpl implements ValidatorMethodValidator {
  
  	private static final Log log = LoggerFactory.make();

The default group array used in case any of the validate methods is called without a group.
  
  	private static final Class<?>[] DEFAULT_GROUP_ARRAY = new Class<?>[] { Default.class };

Used to resolve the group execution order for a validate call.
  
  	private final transient ValidationOrderGenerator validationOrderGenerator;

Reference to shared ConstraintValidatorFactory.
  
javax.validation.MessageInterpolator as passed to the constructor of this instance.
  
javax.validation.TraversableResolver as passed to the constructor of this instance. Never use it directly, always use getCachingTraversableResolver() to retrieved the single threaded caching wrapper.
  
Used to get access to the bean meta data. Used to avoid to parsing the constraint configuration for each call of a given entity.
 
Indicates if validation has to be stopped on first constraint violation.
 
 	private final boolean failFast;
 
 	public ValidatorImpl(ConstraintValidatorFactory constraintValidatorFactoryMessageInterpolator messageInterpolatorTraversableResolver traversableResolverBeanMetaDataManager beanMetaDataManagerboolean failFast) {
 		this. = constraintValidatorFactory;
 		this. = messageInterpolator;
 		this. = traversableResolver;
 		this. = beanMetaDataManager;
 		this. = failFast;
 
 	}
 
 	public final <T> Set<ConstraintViolation<T>> validate(T objectClass<?>... groups) {
 
 
 		ValidationOrder validationOrder = determineGroupValidationOrdergroups );
 
 		ValidationContext<T, ConstraintViolation<T>> validationContext = ValidationContext.getContextForValidate(
 		);
 
 		ValueContext<?, T> valueContext = ValueContext.getLocalExecutionContextobject, PathImpl.createRootPath() );
 
 		return validateInContextvalueContextvalidationContextvalidationOrder );
 	}
 
 	public final <T> Set<ConstraintViolation<T>> validateProperty(T objectString propertyNameClass<?>... groups) {
 
 
 		sanityCheckPropertyPathpropertyName );
 		ValidationOrder validationOrder = determineGroupValidationOrdergroups );
 
 				object,
 		);
 
 		return validatePropertyInContextcontext, PathImpl.createPathFromStringpropertyName ), validationOrder );
 	}
 
 	public final <T> Set<ConstraintViolation<T>> validateValue(Class<T> beanTypeString propertyNameObject valueClass<?>... groups) {
 
 		Contracts.assertNotNullbeanType.beanTypeCannotBeNull() );
 
 		sanityCheckPropertyPathpropertyName );
 		ValidationOrder validationOrder = determineGroupValidationOrdergroups );
 
 		ValidationContext<T, ConstraintViolation<T>> context = ValidationContext.getContextForValidateValue(
 				beanType,
 		);
 
 		return validateValueInContextcontextvalue, PathImpl.createPathFromStringpropertyName ), validationOrder );
 	}
 
 	public final <T> Set<MethodConstraintViolation<T>> validateParameter(T objectMethod methodObject parameterValueint parameterIndexClass<?>... groups) {
 
 
 		ValidationOrder validationOrder = determineGroupValidationOrdergroups );
 
 		MethodValidationContext<T> context = ValidationContext.getContextForValidateParameter(
 				method,
 				parameterIndex,
 				object,
 		);
 
 		Object[] parameterValues = new Object[method.getParameterTypes().length];
 		parameterValues[parameterIndex] = parameterValue;
 
 		validateParametersInContextcontextobjectparameterValuesvalidationOrder );
 
 		return context.getFailingConstraints();
 	}
 
 	public final <T> Set<MethodConstraintViolation<T>> validateAllParameters(T objectMethod methodObject[] parameterValuesClass<?>... groups) {
 
 
 		//this might be the case for parameterless methods
 		if ( parameterValues == null ) {
 			return Collections.emptySet();
 		}
 
 		ValidationOrder validationOrder = determineGroupValidationOrdergroups );
 
 		MethodValidationContext<T> context = ValidationContext.getContextForValidateParameters(
 				method,
 				object,
 		);
 
 		validateParametersInContextcontextobjectparameterValuesvalidationOrder );
 
 		return context.getFailingConstraints();
 	}
 
 	public <T> Set<MethodConstraintViolation<T>> validateReturnValue(T objectMethod methodObject returnValueClass<?>... groups) {
 
 
 		ValidationOrder validationOrder = determineGroupValidationOrdergroups );
 
 		MethodValidationContext<T> context = ValidationContext.getContextForValidateParameters(
 				method,
 				object,
 		);
 
 		validateReturnValueInContextcontextobjectreturnValuevalidationOrder );
 
 		return context.getFailingConstraints();
 	}
 
 	public final BeanDescriptor getConstraintsForClass(Class<?> clazz) {
 	}
 
 	public final TypeDescriptor getConstraintsForType(Class<?> clazz) {
 	}
 
 	public final <T> T unwrap(Class<T> type) {
 		if ( type.isAssignableFromgetClass() ) ) {
 			return type.castthis );
 		}
 	}
 
 	private void sanityCheckPropertyPath(String propertyName) {
 		if ( propertyName == null || propertyName.length() == 0 ) {
 		}
 	}
 
 		Contracts.assertNotNullgroups.groupMustNotBeNull() );
 
 		Class<?>[] tmpGroups = groups;
 		// if no groups is specified use the default
 		if ( tmpGroups.length == 0 ) {
 			tmpGroups = ;
 		}
 
 		return .getValidationOrder( Arrays.asListtmpGroups ) );
 	}

Validates the given object using the available context information.

Parameters:
valueContext the current validation context
context the global validation context
validationOrder Contains the information which and in which order groups have to be executed
<T> The root bean type
<V> The type of the current object on the validation stack
Returns:
Set of constraint violations or the empty set if there were no violations.
 
 	private <T, U, V, E extends ConstraintViolation<T>> Set<E> validateInContext(ValueContext<U, V> valueContextValidationContext<T, E> contextValidationOrder validationOrder) {
 		if ( valueContext.getCurrentBean() == null ) {
 			return Collections.emptySet();
 		}
 
 		BeanMetaData<U> beanMetaData = .getBeanMetaDatavalueContext.getCurrentBeanType() );
 		if ( beanMetaData.defaultGroupSequenceIsRedefined() ) {
 			validationOrder.assertDefaultGroupSequenceIsExpandablebeanMetaData.getDefaultGroupSequencevalueContext.getCurrentBean() ) );
 		}
 
 		// process first single groups. For these we can optimise object traversal by first running all validations on the current bean
 		// before traversing the object.
 		Iterator<GroupgroupIterator = validationOrder.getGroupIterator();
 		while ( groupIterator.hasNext() ) {
 			Group group = groupIterator.next();
 			valueContext.setCurrentGroupgroup.getDefiningClass() );
 			validateConstraintsForCurrentGroupcontextvalueContext );
 			if ( shouldFailFastcontext ) ) {
 				return context.getFailingConstraints();
 			}
 		}
 		groupIterator = validationOrder.getGroupIterator();
 		while ( groupIterator.hasNext() ) {
 			Group group = groupIterator.next();
 			valueContext.setCurrentGroupgroup.getDefiningClass() );
 			validateCascadedConstraintscontextvalueContext );
 			if ( shouldFailFastcontext ) ) {
 				return context.getFailingConstraints();
 			}
 		}
 
 		// now we process sequences. For sequences I have to traverse the object graph since I have to stop processing when an error occurs.
 		Iterator<SequencesequenceIterator = validationOrder.getSequenceIterator();
 		while ( sequenceIterator.hasNext() ) {
 			Sequence sequence = sequenceIterator.next();
 			for ( Group group : sequence.getComposingGroups() ) {
 				int numberOfViolations = context.getFailingConstraints().size();
 				valueContext.setCurrentGroupgroup.getDefiningClass() );
 
 				validateConstraintsForCurrentGroupcontextvalueContext );
 				if ( shouldFailFastcontext ) ) {
 					return context.getFailingConstraints();
 				}
 
 				validateCascadedConstraintscontextvalueContext );
 				if ( shouldFailFastcontext ) ) {
 					return context.getFailingConstraints();
 				}
 
 				if ( context.getFailingConstraints().size() > numberOfViolations ) {
 					break;
 				}
 			}
 		}
 		return context.getFailingConstraints();
 	}
 
 	private <T, U, V, E extends ConstraintViolation<T>> void validateConstraintsForCurrentGroup(ValidationContext<T, E> validationContextValueContext<U, V> valueContext) {
 		// we are not validating the default group there is nothing special to consider. If we are validating the default
 		// group sequence we have to consider that a class in the hierarchy could redefine the default group sequence.
 		if ( !valueContext.validatingDefault() ) {
 			validateConstraintsForNonDefaultGroupvalidationContextvalueContext );
 		}
 		else {
 			validateConstraintsForDefaultGroupvalidationContextvalueContext );
 		}
 	}
 
 	private <T, U, V, E extends ConstraintViolation<T>> void validateConstraintsForDefaultGroup(ValidationContext<T, E> validationContextValueContext<U, V> valueContext) {
 		final BeanMetaData<U> beanMetaData = .getBeanMetaDatavalueContext.getCurrentBeanType() );
 		final Map<Class<?>, Class<?>> validatedInterfaces = newHashMap();
 
 		// evaluating the constraints of a bean per class in hierarchy, this is necessary to detect potential default group re-definitions
 		for ( Class<?> clazz : beanMetaData.getClassHierarchy() ) {
 			BeanMetaData<U> hostingBeanMetaData = (BeanMetaData<U>) .getBeanMetaDataclazz );
 			boolean defaultGroupSequenceIsRedefined = hostingBeanMetaData.defaultGroupSequenceIsRedefined();
 			List<Class<?>> defaultGroupSequence = hostingBeanMetaData.getDefaultGroupSequencevalueContext.getCurrentBean() );
 			Set<MetaConstraint<?>> metaConstraints = hostingBeanMetaData.getDirectMetaConstraints();
 
 			// if the current class redefined the default group sequence, this sequence has to be applied to all the class hierarchy.
 			if ( defaultGroupSequenceIsRedefined ) {
 				metaConstraints = hostingBeanMetaData.getMetaConstraints();
 			}
 
 			PathImpl currentPath = valueContext.getPropertyPath();
 			for ( Class<?> defaultSequenceMember : defaultGroupSequence ) {
 				valueContext.setCurrentGroupdefaultSequenceMember );
 				boolean validationSuccessful = true;
 				for ( MetaConstraint<?> metaConstraint : metaConstraints ) {
 					// HV-466, an interface implemented more than one time in the hierarchy has to be validated only one
 					// time. An interface can define more than one constraint, we have to check the class we are validating.
 					final Class<?> declaringClass = metaConstraint.getLocation().getBeanClass();
 					if ( declaringClass.isInterface() ) {
 						Class<?> validatedForClass = validatedInterfaces.getdeclaringClass );
 						if ( validatedForClass != null && !validatedForClass.equalsclazz ) ) {
 							continue;
 						}
 						validatedInterfaces.putdeclaringClassclazz );
 					}
 
 					boolean tmp = validateConstraint(
 							validationContextvalueContextmetaConstraint
 					);
 					if ( shouldFailFastvalidationContext ) ) {
 						return;
 					}
 					validationSuccessful = validationSuccessful && tmp;
 					valueContext.setPropertyPathcurrentPath );
 				}
 				if ( !validationSuccessful ) {
 					break;
 				}
 			}
 			validationContext.markProcessed(
 					valueContext.getCurrentBean(),
 					valueContext.getCurrentGroup(),
 					valueContext.getPropertyPath()
 			);
 
 			// all constraints in the hierarchy has been validated, stop validation.
 			if ( defaultGroupSequenceIsRedefined ) {
 				break;
 			}
 		}
 	}
 
 	private <T, U, V> void validateConstraintsForNonDefaultGroup(ValidationContext<T, ?> validationContextValueContext<U, V> valueContext) {
 		BeanMetaData<U> beanMetaData = .getBeanMetaDatavalueContext.getCurrentBeanType() );
 		PathImpl currentPath = valueContext.getPropertyPath();
 		for ( MetaConstraint<?> metaConstraint : beanMetaData.getMetaConstraints() ) {
 			validateConstraintvalidationContextvalueContextmetaConstraint );
 			if ( shouldFailFastvalidationContext ) ) {
 				return;
 			}
 			// reset the path to the state before this call
 			valueContext.setPropertyPathcurrentPath );
 		}
 		validationContext.markProcessed(
 				valueContext.getCurrentBean(),
 				valueContext.getCurrentGroup(),
 				valueContext.getPropertyPath()
 		);
 	}
 
 	private <T, U, V> boolean validateConstraint(ValidationContext<T, ?> validationContextValueContext<U, V> valueContextMetaConstraint<?> metaConstraint) {
 		boolean validationSuccessful = true;
 
 		if ( metaConstraint.getElementType() != . ) {
 			valueContext.appendNode( ReflectionHelper.getPropertyNamemetaConstraint.getLocation().getMember() ) );
 		}
 
 		if ( isValidationRequiredvalidationContextvalueContextmetaConstraint ) ) {
 			@SuppressWarnings("unchecked")
 			V valueToValidate = (V) metaConstraint.getValuevalueContext.getCurrentBean() );
 			valueContext.setCurrentValidatedValuevalueToValidate );
 			validationSuccessful = metaConstraint.validateConstraintvalidationContextvalueContext );
 		}
 
 		return validationSuccessful;
 	}

Validates all cascaded constraints for the given bean using the current group set in the execution context. This method must always be called after validateConstraints for the same context.

Parameters:
validationContext The execution context
valueContext Collected information for single validation
 
 	private <T, U, V> void validateCascadedConstraints(ValidationContext<T, ?> validationContextValueContext<U, V> valueContext) {
 		Set<MembercascadedMembers = .getBeanMetaDatavalueContext.getCurrentBeanType() )
 		PathImpl currentPath = valueContext.getPropertyPath();
 		for ( Member member : cascadedMembers ) {
 			String newNode = ReflectionHelper.getPropertyNamemember );
 			valueContext.appendNodenewNode );
 
 			if ( isCascadeRequiredvalidationContextvalueContextmember ) ) {
 				Object value = ReflectionHelper.getValuemembervalueContext.getCurrentBean() );
 				if ( value != null ) {
 					Type type = value.getClass();
 					Iterator<?> iter = createIteratorForCascadedValuetypevaluevalueContext );
 					boolean isIndexable = isIndexabletype );
 							validationContext,
 							iter,
 							isIndexable,
 							valueContext
 					);
 					if ( shouldFailFastvalidationContext ) ) {
 						return;
 					}
 				}
 			}
 			// reset the path
 			valueContext.setPropertyPathcurrentPath );
 		}
 	}

Validates the cascading parameter or return value specified with the given value context. Any further cascading references are followed if applicable.

Parameters:
validationContext The global context for the current validateParameter(s) or validateReturnValue() call.
valueContext The local context for validating the given parameter/return value.
 
 	private <T, U, V> void validateCascadedMethodConstraints(MethodValidationContext<T> validationContextValueContext<U, V> valueContext) {
 
 		Object value = valueContext.getCurrentBean();
 		Type type = valueContext.getCurrentBeanType();
 		Iterator<?> iter = createIteratorForCascadedValuetypevaluevalueContext );
 		boolean isIndexable = isIndexabletype );
 
 				validationContext,
 				iter,
 				isIndexable,
 				valueContext
 		);
 	}

Called when processing cascaded constraints. This methods inspects the type of the cascaded constraints and in case of a list or array creates an iterator in order to validate each element.

Parameters:
type the type of the cascaded field or property.
value the actual value.
valueContext context object containing state about the currently validated instance
Returns:
An iterator over the value of a cascaded property.
 
 	private Iterator<?> createIteratorForCascadedValue(Type typeObject valueValueContext<?, ?> valueContext) {
 		Iterator<?> iter;
 		if ( ReflectionHelper.isIterabletype ) ) {
 			iter = ( (Iterable<?>) value ).iterator();
 		}
 		else if ( ReflectionHelper.isMaptype ) ) {
 			Map<?, ?> map = (Map<?, ?>) value;
 			iter = map.entrySet().iterator();
 		}
 		else if ( TypeHelper.isArraytype ) ) {
 			List<?> arrayList = Arrays.asList( (Object[]) value );
 			iter = arrayList.iterator();
 		}
 		else {
 			List<Objectlist = newArrayList();
 			list.addvalue );
 			iter = list.iterator();
 		}
 		return iter;
 	}

Called when processing cascaded constraints. This methods inspects the type of the cascaded constraints and in case of a list or array creates an iterator in order to validate each element.

Parameters:
type the type of the cascaded field or property.
Returns:
An iterator over the value of a cascaded property.
 
 	private boolean isIndexable(Type type) {
 		boolean isIndexable = false;
 		if ( ReflectionHelper.isListtype ) ) {
 			isIndexable = true;
 		}
 		else if ( ReflectionHelper.isMaptype ) ) {
 			isIndexable = true;
 		}
 		else if ( TypeHelper.isArraytype ) ) {
 			isIndexable = true;
 		}
 		return isIndexable;
 	}
 
 	private <T> void validateCascadedConstraint(ValidationContext<T, ?> contextIterator<?> iterboolean isIndexableValueContext<?, ?> valueContext) {
 		Object value;
 		Object mapKey;
 		int i = 0;
 		while ( iter.hasNext() ) {
 			value = iter.next();
 			if ( value instanceof Map.Entry ) {
 				mapKey = ( (Map.Entry<?, ?>) value ).getKey();
 				valueContext.setKeymapKey );
 				value = ( (Map.Entry<?, ?>) value ).getValue();
 			}
 			else if ( isIndexable ) {
 				valueContext.setIndexi );
 			}
 
 			if ( !context.isAlreadyValidated(
 					valuevalueContext.getCurrentGroup(), valueContext.getPropertyPath()
 			) ) {
 						Arrays.<Class<?>>asListvalueContext.getCurrentGroup() )
 				);
 
 				ValueContext<?, T> newValueContext;
 				if ( value != null ) {
 					newValueContext = ValueContext.getLocalExecutionContextvaluevalueContext.getPropertyPath() );
 				}
 				else {
 					newValueContext = ValueContext.getLocalExecutionContext(
 							valueContext.getCurrentBeanType(), valueContext.getPropertyPath()
 					);
 				}
 
 				//propagate parameter index/name if required
 				if ( valueContext.getParameterIndex() != null ) {
 					newValueContext.setParameterIndexvalueContext.getParameterIndex() );
 					newValueContext.setParameterNamevalueContext.getParameterName() );
 				}
 
 				validateInContextnewValueContextcontextvalidationOrder );
 				if ( shouldFailFastcontext ) ) {
 					return;
 				}
 			}
 			i++;
 		}
 	}
 
 	private <T, U, V> Set<ConstraintViolation<T>> validatePropertyInContext(ValidationContext<T, ConstraintViolation<T>> contextPathImpl propertyPathValidationOrder validationOrder) {
 		List<MetaConstraint<?>> metaConstraints = newArrayList();
 		Iterator<Path.NodepropertyIter = propertyPath.iterator();
 		ValueContext<U, V> valueContext = collectMetaConstraintsForPath(
 				context.getRootBeanClass(),
 				context.getRootBean(),
 				propertyIter,
 				propertyPath,
 				metaConstraints
 		);
 
 		if ( valueContext.getCurrentBean() == null ) {
 		}
 
 		if ( metaConstraints.size() == 0 ) {
 			return context.getFailingConstraints();
 		}
 
 		BeanMetaData<U> beanMetaData = .getBeanMetaDatavalueContext.getCurrentBeanType() );
 		if ( beanMetaData.defaultGroupSequenceIsRedefined() ) {
 			validationOrder.assertDefaultGroupSequenceIsExpandablebeanMetaData.getDefaultGroupSequencevalueContext.getCurrentBean() ) );
 		}
 
 		// process first single groups
 		Iterator<GroupgroupIterator = validationOrder.getGroupIterator();
 		while ( groupIterator.hasNext() ) {
 			Group group = groupIterator.next();
 			valueContext.setCurrentGroupgroup.getDefiningClass() );
 			validatePropertyForCurrentGroupvalueContextcontextmetaConstraints );
 			if ( shouldFailFastcontext ) ) {
 				return context.getFailingConstraints();
 			}
 		}
 
 		// now process sequences, stop after the first erroneous group
 		Iterator<SequencesequenceIterator = validationOrder.getSequenceIterator();
 		while ( sequenceIterator.hasNext() ) {
 			Sequence sequence = sequenceIterator.next();
 			for ( Group group : sequence.getComposingGroups() ) {
 				valueContext.setCurrentGroupgroup.getDefiningClass() );
 				int numberOfConstraintViolations = validatePropertyForCurrentGroup(
 						valueContextcontextmetaConstraints
 				);
 				if ( shouldFailFastcontext ) ) {
 					return context.getFailingConstraints();
 				}
 				if ( numberOfConstraintViolations > 0 ) {
 					break;
 				}
 			}
 		}
 
 		return context.getFailingConstraints();
 	}
 
 	private <T, U, V> Set<ConstraintViolation<T>> validateValueInContext(ValidationContext<T, ConstraintViolation<T>> context, V valuePathImpl propertyPathValidationOrder validationOrder) {
 		List<MetaConstraint<?>> metaConstraints = newArrayList();
 		ValueContext<U, V> valueContext = collectMetaConstraintsForPath(
 				context.getRootBeanClass(), nullpropertyPath.iterator(), propertyPathmetaConstraints
 		);
 		valueContext.setCurrentValidatedValuevalue );
 
 		if ( metaConstraints.size() == 0 ) {
 			return context.getFailingConstraints();
 		}
 
 		BeanMetaData<U> beanMetaData = .getBeanMetaDatavalueContext.getCurrentBeanType() );
 		if ( beanMetaData.defaultGroupSequenceIsRedefined() ) {
 			validationOrder.assertDefaultGroupSequenceIsExpandablebeanMetaData.getDefaultGroupSequencenull ) );
 		}
 
 		// process first single groups
 		Iterator<GroupgroupIterator = validationOrder.getGroupIterator();
 		while ( groupIterator.hasNext() ) {
 			Group group = groupIterator.next();
 			valueContext.setCurrentGroupgroup.getDefiningClass() );
 			validatePropertyForCurrentGroupvalueContextcontextmetaConstraints );
 			if ( shouldFailFastcontext ) ) {
 				return context.getFailingConstraints();
 			}
 		}
 
 		// now process sequences, stop after the first erroneous group
 		Iterator<SequencesequenceIterator = validationOrder.getSequenceIterator();
 		while ( sequenceIterator.hasNext() ) {
 			Sequence sequence = sequenceIterator.next();
 			for ( Group group : sequence.getComposingGroups() ) {
 				valueContext.setCurrentGroupgroup.getDefiningClass() );
 				int numberOfConstraintViolations = validatePropertyForCurrentGroup(
 						valueContextcontextmetaConstraints
 				);
 				if ( shouldFailFastcontext ) ) {
 					return context.getFailingConstraints();
 				}
 				if ( numberOfConstraintViolations > 0 ) {
 					break;
 				}
 			}
 		}
 
 		return context.getFailingConstraints();
 	}

Validates the property constraints associated to the current ValueContext group.

Parameters:
valueContext The current validation context.
validationContext The global validation context.
metaConstraints All constraints associated to the property.
Returns:
The number of constraint violations raised when validating the ValueContext current group.
 
 	private <T, U, V> int validatePropertyForCurrentGroup(ValueContext<U, V> valueContextValidationContext<T, ConstraintViolation<T>> validationContextList<MetaConstraint<?>> metaConstraints) {
 		// we do not validate the default group, nothing special to do
 		if ( !valueContext.validatingDefault() ) {
 			return validatePropertyForNonDefaultGroupvalueContextvalidationContextmetaConstraints );
 		}
 
 		// we are validating the default group, we have to consider that a class in the hierarchy could redefine the default group sequence
 		return validatePropertyForDefaultGroupvalueContextvalidationContextmetaConstraints );
 	}

Validates the property constraints for the current ValueContext group.

The current ValueContext group is not the default group.

Parameters:
valueContext The current validation context.
validationContext The global validation context.
metaConstraints All constraints associated to the property.
Returns:
The number of constraint violations raised when validating the ValueContext current group.
 
 	private <T, U, V> int validatePropertyForNonDefaultGroup(ValueContext<U, V> valueContextValidationContext<T, ConstraintViolation<T>> validationContextList<MetaConstraint<?>> metaConstraints) {
 		int numberOfConstraintViolationsBefore = validationContext.getFailingConstraints().size();
 
 		for ( MetaConstraint<?> metaConstraint : metaConstraints ) {
 			if ( isValidationRequiredvalidationContextvalueContextmetaConstraint ) ) {
 				if ( valueContext.getCurrentBean() != null ) {
 					@SuppressWarnings("unchecked")
 					V valueToValidate = (V) metaConstraint.getValuevalueContext.getCurrentBean() );
 					valueContext.setCurrentValidatedValuevalueToValidate );
 				}
 				metaConstraint.validateConstraintvalidationContextvalueContext );
 				if ( shouldFailFastvalidationContext ) ) {
 					return validationContext.getFailingConstraints()
 							.size() - numberOfConstraintViolationsBefore;
 				}
 			}
 		}
 		return validationContext.getFailingConstraints().size() - numberOfConstraintViolationsBefore;
 	}

Validates the property for the default group.

This method checks that the default group sequence is not redefined in the class hierarchy for a superclass hosting constraints for the property to validate.

Parameters:
valueContext The current validation context.
validationContext The global validation context.
constraintList All constraints associated to the property to check.
Returns:
The number of constraint violations raised when validating the default group.
 
 	private <T, U, V> int validatePropertyForDefaultGroup(ValueContext<U, V> valueContextValidationContext<T, ConstraintViolation<T>> validationContextList<MetaConstraint<?>> constraintList) {
 		final int numberOfConstraintViolationsBefore = validationContext.getFailingConstraints().size();
 		final BeanMetaData<U> beanMetaData = .getBeanMetaDatavalueContext.getCurrentBeanType() );
 		final Map<Class<?>, Class<?>> validatedInterfaces = newHashMap();
 
 		// evaluating the constraints of a bean per class in hierarchy. this is necessary to detect potential default group re-definitions
 		for ( Class<?> clazz : beanMetaData.getClassHierarchy() ) {
 			BeanMetaData<U> hostingBeanMetaData = (BeanMetaData<U>) .getBeanMetaDataclazz );
 			boolean defaultGroupSequenceIsRedefined = hostingBeanMetaData.defaultGroupSequenceIsRedefined();
 			Set<MetaConstraint<?>> metaConstraints = hostingBeanMetaData.getDirectMetaConstraints();
 			List<Class<?>> defaultGroupSequence = hostingBeanMetaData.getDefaultGroupSequencevalueContext.getCurrentBean() );
 
 			if ( defaultGroupSequenceIsRedefined ) {
 				metaConstraints = hostingBeanMetaData.getMetaConstraints();
 			}
 
 			for ( Class<?> groupClass : defaultGroupSequence ) {
 				boolean validationSuccessful = true;
 				valueContext.setCurrentGroupgroupClass );
 				for ( MetaConstraint<?> metaConstraint : metaConstraints ) {
 					// HV-466, an interface implemented more than one time in the hierarchy has to be validated only one
 					// time. An interface can define more than one constraint, we have to check the class we are validating.
 					final Class<?> declaringClass = metaConstraint.getLocation().getBeanClass();
 					if ( declaringClass.isInterface() ) {
 						Class<?> validatedForClass = validatedInterfaces.getdeclaringClass );
 						if ( validatedForClass != null && !validatedForClass.equalsclazz ) ) {
 							continue;
 						}
 						validatedInterfaces.putdeclaringClassclazz );
 					}
 
 					if ( constraintList.containsmetaConstraint )
 							&& isValidationRequiredvalidationContextvalueContextmetaConstraint ) ) {
 
 						if ( valueContext.getCurrentBean() != null ) {
 							@SuppressWarnings("unchecked")
 							V valueToValidate = (V) metaConstraint.getValuevalueContext.getCurrentBean() );
 							valueContext.setCurrentValidatedValuevalueToValidate );
 						}
 						boolean tmp = metaConstraint.validateConstraintvalidationContextvalueContext );
 						validationSuccessful = validationSuccessful && tmp;
 						if ( shouldFailFastvalidationContext ) ) {
 							return validationContext.getFailingConstraints()
 									.size() - numberOfConstraintViolationsBefore;
 						}
 					}
 				}
 				if ( !validationSuccessful ) {
 					break;
 				}
 			}
 			// all the hierarchy has been validated, stop validation.
 			if ( defaultGroupSequenceIsRedefined ) {
 				break;
 			}
 		}
 		return validationContext.getFailingConstraints().size() - numberOfConstraintViolationsBefore;
 	}
 
 	private <T> void validateParametersInContext(MethodValidationContext<T> validationContext, T objectObject[] parameterValuesValidationOrder validationOrder) {
 
 		BeanMetaData<T> beanMetaData = .getBeanMetaDatavalidationContext.getRootBeanClass() );
 
 		//assert that there are no illegal method parameter constraints
 		MethodMetaData methodMetaData = beanMetaData.getMetaDataForvalidationContext.getMethod() );
 
 		if ( beanMetaData.defaultGroupSequenceIsRedefined() ) {
 			validationOrder.assertDefaultGroupSequenceIsExpandablebeanMetaData.getDefaultGroupSequenceobject ) );
 		}
 
 		// process first single groups
 		Iterator<GroupgroupIterator = validationOrder.getGroupIterator();
 		while ( groupIterator.hasNext() ) {
 			validateParametersForGroupvalidationContextobjectparameterValuesgroupIterator.next() );
 			if ( shouldFailFastvalidationContext ) ) {
 				return;
 			}
 		}
 
 		// now process sequences, stop after the first erroneous group
 		Iterator<SequencesequenceIterator = validationOrder.getSequenceIterator();
 		while ( sequenceIterator.hasNext() ) {
 			Sequence sequence = sequenceIterator.next();
 			for ( Group group : sequence.getComposingGroups() ) {
 				int numberOfFailingConstraint = validateParametersForGroup(
 						validationContextobjectparameterValuesgroup
 				);
 				if ( shouldFailFastvalidationContext ) ) {
 					return;
 				}
 				if ( numberOfFailingConstraint > 0 ) {
 					break;
 				}
 			}
 		}
 	}
 
 	private <T> int validateParametersForGroup(MethodValidationContext<T> validationContext, T objectObject[] parameterValuesGroup group) {
 
 		int numberOfViolationsBefore = validationContext.getFailingConstraints().size();
 
 		Method method = validationContext.getMethod();
 
 		BeanMetaData<T> beanMetaData = .getBeanMetaDatavalidationContext.getRootBeanClass() );
 		MethodMetaData methodMetaData = beanMetaData.getMetaDataFormethod );
 
 		// TODO GM: define behavior with respect to redefined default sequences. Should only the
 		// sequence from the validated bean be honored or also default sequence definitions up in
 		// the inheritance tree?
 		// For now a redefined default sequence will only be considered if specified at the bean
 		// hosting the validated itself, but no other default sequence from parent types
 
 		List<Class<?>> groupList;
 		if ( group.isDefaultGroup() ) {
 			groupList = beanMetaData.getDefaultGroupSequenceobject );
 		}
 		else {
 			groupList = Arrays.<Class<?>>asListgroup.getDefiningClass() );
 		}
 
 		//the only case where we can have multiple groups here is a redefined default group sequence
 		for ( Class<?> oneGroup : groupList ) {
 
 			int numberOfViolationsOfCurrentGroup = 0;
 
 			for ( int i = 0; i < parameterValues.lengthi++ ) {
 
 				//ignore this parameter if this validation is for a single parameter and this is not the right one
 				if ( validationContext.getParameterIndex() != null && !validationContext.getParameterIndex()
 						.equalsi ) ) {
 					continue;
 				}
 
 				Object value = parameterValues[i];
 				String parameterName = methodMetaData.getParameterMetaDatai ).getName();
 
 				// validate constraints at parameter itself
 				ValueContext<T, ObjectvalueContext = ValueContext.getLocalExecutionContext(
 						object, PathImpl.createPathForMethodParametermethodparameterName ), iparameterName
 				);
 				valueContext.setCurrentValidatedValuevalue );
 				valueContext.setCurrentGrouponeGroup );
 
 				numberOfViolationsOfCurrentGroup += validateParameterForGroup(
 						validationContextvalueContextmethodMetaData.getParameterMetaDatai )
 				);
 				if ( shouldFailFastvalidationContext ) ) {
 					return validationContext.getFailingConstraints().size() - numberOfViolationsBefore;
 				}
 			}
 
 			//stop processing after first group with errors occurred
 			if ( numberOfViolationsOfCurrentGroup > 0 ) {
 				break;
 			}
 		}
 
 		// validate parameter beans annotated with @Valid if required
 		for ( int i = 0; i < parameterValues.lengthi++ ) {
 
 			//ignore this parameter if this validation is for a single parameter and this is not the right one
 			if ( validationContext.getParameterIndex() != null && !validationContext.getParameterIndex().equalsi ) ) {
 				continue;
 			}
 
 			Object value = parameterValues[i];
 			ParameterMetaData parameterMetaData = methodMetaData.getParameterMetaDatai );
 			String parameterName = parameterMetaData.getName();
 
 			if ( parameterMetaData.isCascading() && value != null ) {
 
 				ValueContext<Object, ?> cascadingvalueContext = ValueContext.getLocalExecutionContext(
 						value, PathImpl.createPathForMethodParametermethodparameterName ), iparameterName
 				);
 				cascadingvalueContext.setCurrentGroupgroup.getDefiningClass() );
 
 				//TODO GM: consider violations from cascaded validation
 				validateCascadedMethodConstraintsvalidationContextcascadingvalueContext );
 				if ( shouldFailFastvalidationContext ) ) {
 					break;
 				}
 			}
 		}
 
 		return validationContext.getFailingConstraints().size() - numberOfViolationsBefore;
 	}

Validates the constraints at the specified parameter which are part of the given value context's current group. Any occurred constraint violations are stored in the given validation context.

Parameters:
validationContext The validation context for storing constraint violations.
valueContext The value context specifying the group and value to validate.
parameterMetaData Meta data on the constraints to evaluate.
Returns:
The number of constraint violations occurred during validation of the specified constraints.
 
 	private <T, U, V> int validateParameterForGroup(MethodValidationContext<T> validationContextValueContext<U, V> valueContextParameterMetaData parameterMetaData) {
 
 		int numberOfViolationsBefore = validationContext.getFailingConstraints().size();
 
 		for ( MetaConstraint<?> metaConstraint : parameterMetaData ) {
 
 			//ignore constraints not part of the evaluated group
 			if ( !metaConstraint.getGroupList().containsvalueContext.getCurrentGroup() ) ) {
 				continue;
 			}
 
 			metaConstraint.validateConstraintvalidationContextvalueContext );
 			if ( shouldFailFastvalidationContext ) ) {
 				break;
 			}
 		}
 
 		return validationContext.getFailingConstraints().size() - numberOfViolationsBefore;
 	}
	private <V, T> void validateReturnValueInContext(MethodValidationContext<T> context, T bean, V valueValidationOrder validationOrder) {
		if ( beanMetaData.defaultGroupSequenceIsRedefined() ) {
			validationOrder.assertDefaultGroupSequenceIsExpandablebeanMetaData.getDefaultGroupSequencebean ) );
		Iterator<GroupgroupIterator = validationOrder.getGroupIterator();
		// process first single groups
		while ( groupIterator.hasNext() ) {
			validateReturnValueForGroupcontextbeanvaluegroupIterator.next() );
			if ( shouldFailFastcontext ) ) {
				return;
		// now process sequences, stop after the first erroneous group
		Iterator<SequencesequenceIterator = validationOrder.getSequenceIterator();
		while ( sequenceIterator.hasNext() ) {
			Sequence sequence = sequenceIterator.next();
			for ( Group group : sequence.getComposingGroups() ) {
				int numberOfFailingConstraint = validateReturnValueForGroup(
						contextbeanvaluegroup
				);
				if ( shouldFailFastcontext ) ) {
					return;
				if ( numberOfFailingConstraint > 0 ) {
					break;
	//TODO GM: if possible integrate with validateParameterForGroup()
	private <T, V> int validateReturnValueForGroup(MethodValidationContext<T> validationContext, T bean, V valueGroup group) {
		int numberOfViolationsBefore = validationContext.getFailingConstraints().size();
		Method method = validationContext.getMethod();
		BeanMetaData<T> beanMetaData = .getBeanMetaDatavalidationContext.getRootBeanClass() );
		MethodMetaData methodMetaData = beanMetaData.getMetaDataFormethod );
		// TODO GM: define behavior with respect to redefined default sequences. Should only the
		// sequence from the validated bean be honored or also default sequence definitions up in
		// the inheritance tree?
		// For now a redefined default sequence will only be considered if specified at the bean
		// hosting the validated itself, but no other default sequence from parent types
		List<Class<?>> groupList;
		if ( group.isDefaultGroup() ) {
			groupList = beanMetaData.getDefaultGroupSequencebean );
		else {
			groupList = Arrays.<Class<?>>asListgroup.getDefiningClass() );
		//the only case where we can have multiple groups here is a redefined default group sequence
		for ( Class<?> oneGroup : groupList ) {
			int numberOfViolationsOfCurrentGroup = 0;
			// validate constraints at return value itself
			ValueContext<T, V> valueContext = ValueContext.getLocalExecutionContext(
					bean, PathImpl.createPathForMethodReturnValuemethod )
			);
			valueContext.setCurrentValidatedValuevalue );
			valueContext.setCurrentGrouponeGroup );
			numberOfViolationsOfCurrentGroup +=
							validationContextvalueContextmethodMetaData
					);
			if ( shouldFailFastvalidationContext ) ) {
				return validationContext.getFailingConstraints().size() - numberOfViolationsBefore;
			//stop processing after first group with errors occurred
			if ( numberOfViolationsOfCurrentGroup > 0 ) {
				break;
		// cascaded validation if required
		if ( methodMetaData.isCascading() && value != null ) {
			ValueContext<V, ObjectcascadingvalueContext = ValueContext.getLocalExecutionContext(
					value, PathImpl.createPathForMethodReturnValuemethod )
			);
			cascadingvalueContext.setCurrentGroupgroup.getDefiningClass() );
			validateCascadedMethodConstraintsvalidationContextcascadingvalueContext );
		return validationContext.getFailingConstraints().size() - numberOfViolationsBefore;
	private <T, V> int validateReturnValueForGroup(MethodValidationContext<T> validationContext,
												   ValueContext<T, V> valueContextMethodMetaData methodMetaData) {
		int numberOfViolationsBefore = validationContext.getFailingConstraints().size();
		for ( MetaConstraint<?> metaConstraint : methodMetaData ) {
			if ( !metaConstraint.getGroupList().containsvalueContext.getCurrentGroup() ) ) {
				continue;
			metaConstraint.validateConstraintvalidationContextvalueContext );
			if ( shouldFailFastvalidationContext ) ) {
				break;
		return validationContext.getFailingConstraints().size() - numberOfViolationsBefore;
	}

Collects all MetaConstraints which match the given path relative to the specified root class.

This method is called recursively.

Parameters:
clazz The class type to check for constraints.
value While resolving the property path this instance points to the current object. Might be null.
propertyIter An instance of PropertyIterator in order to iterate the items of the original property path.
propertyPath The property path for which constraints have to be collected.
metaConstraintsList An instance of Map where MetaConstraints which match the given path are saved for each class in the hosting class hierarchy.
Returns:
Returns an instance of ValueContext which describes the local validation context associated to the given property path.
	private <T, U, V> ValueContext<U, V> collectMetaConstraintsForPath(Class<T> clazzObject valueIterator<Path.NodepropertyIterPathImpl propertyPathList<MetaConstraint<?>> metaConstraintsList) {
		Path.Node elem = propertyIter.next();