[hibernate-commits] Hibernate SVN: r19313 - in validator/trunk: hibernate-validator/src/main/java/org/hibernate/validator/metadata and 1 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Wed Apr 28 07:05:28 EDT 2010


Author: hardy.ferentschik
Date: 2010-04-28 07:05:26 -0400 (Wed, 28 Apr 2010)
New Revision: 19313

Added:
   validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ValidationContext.java
   validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ValueContext.java
Removed:
   validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/GlobalExecutionContext.java
   validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/LocalExecutionContext.java
Modified:
   validator/trunk/hibernate-validator-tck-runner/pom.xml
   validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ConstraintTree.java
   validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ValidatorFactoryImpl.java
   validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ValidatorImpl.java
   validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/metadata/BeanMetaDataImpl.java
   validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/metadata/MetaConstraint.java
Log:
HV-317

Modified: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ConstraintTree.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ConstraintTree.java	2010-04-28 04:32:00 UTC (rev 19312)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ConstraintTree.java	2010-04-28 11:05:26 UTC (rev 19313)
@@ -89,16 +89,16 @@
 		return descriptor;
 	}
 
-	public <T, U, V> void validateConstraints(Type type, GlobalExecutionContext<T> executionContext, LocalExecutionContext<U, V> localExecutionContext, List<ConstraintViolation<T>> constraintViolations) {
+	public <T, U, V> void validateConstraints(Type type, ValidationContext<T> executionContext, ValueContext<U, V> valueContext, List<ConstraintViolation<T>> constraintViolations) {
 		// first validate composing constraints (recursively)
 		for ( ConstraintTree<?> tree : getChildren() ) {
 			List<ConstraintViolation<T>> tmpViolations = new ArrayList<ConstraintViolation<T>>();
-			tree.validateConstraints( type, executionContext, localExecutionContext, tmpViolations );
+			tree.validateConstraints( type, executionContext, valueContext, tmpViolations );
 			constraintViolations.addAll( tmpViolations );
 		}
 
 		ConstraintValidatorContextImpl constraintValidatorContext = new ConstraintValidatorContextImpl(
-				localExecutionContext.getPropertyPath(), descriptor
+				valueContext.getPropertyPath(), descriptor
 		);
 
 		// check whether we have constraints violations, but we should only report the single message of the
@@ -108,9 +108,9 @@
 		if ( constraintViolations.size() > 0 && reportAsSingleViolation() ) {
 			constraintViolations.clear();
 			final String message = ( String ) getDescriptor().getAttributes().get( "message" );
-			MessageAndPath messageAndPath = new MessageAndPath( message, localExecutionContext.getPropertyPath() );
+			MessageAndPath messageAndPath = new MessageAndPath( message, valueContext.getPropertyPath() );
 			ConstraintViolation<T> violation = executionContext.createConstraintViolation(
-					localExecutionContext, messageAndPath, descriptor
+					valueContext, messageAndPath, descriptor
 			);
 			constraintViolations.add( violation );
 		}
@@ -120,7 +120,7 @@
 			if ( log.isTraceEnabled() ) {
 				log.trace(
 						"Validating value {} against constraint defined by {}",
-						localExecutionContext.getCurrentValidatedValue(),
+						valueContext.getCurrentValidatedValue(),
 						descriptor
 				);
 			}
@@ -131,7 +131,7 @@
 
 			validateSingleConstraint(
 					executionContext,
-					localExecutionContext,
+					valueContext,
 					constraintViolations,
 					constraintValidatorContext,
 					validator
@@ -139,10 +139,10 @@
 		}
 	}
 
-	private <T, U, V> void validateSingleConstraint(GlobalExecutionContext<T> executionContext, LocalExecutionContext<U, V> localExecutionContext, List<ConstraintViolation<T>> constraintViolations, ConstraintValidatorContextImpl constraintValidatorContext, ConstraintValidator<A, V> validator) {
+	private <T, U, V> void validateSingleConstraint(ValidationContext<T> executionContext, ValueContext<U, V> valueContext, List<ConstraintViolation<T>> constraintViolations, ConstraintValidatorContextImpl constraintValidatorContext, ConstraintValidator<A, V> validator) {
 		boolean isValid;
 		try {
-			isValid = validator.isValid( localExecutionContext.getCurrentValidatedValue(), constraintValidatorContext );
+			isValid = validator.isValid( valueContext.getCurrentValidatedValue(), constraintValidatorContext );
 		}
 		catch ( RuntimeException e ) {
 			throw new ValidationException( "Unexpected exception during isValid call", e );
@@ -150,7 +150,7 @@
 		if ( !isValid ) {
 			constraintViolations.addAll(
 					executionContext.createConstraintViolations(
-							localExecutionContext, constraintValidatorContext
+							valueContext, constraintValidatorContext
 					)
 			);
 		}

Deleted: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/GlobalExecutionContext.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/GlobalExecutionContext.java	2010-04-28 04:32:00 UTC (rev 19312)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/GlobalExecutionContext.java	2010-04-28 11:05:26 UTC (rev 19313)
@@ -1,266 +0,0 @@
-// $Id$
-/*
-* 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.engine;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.IdentityHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import javax.validation.ConstraintValidatorFactory;
-import javax.validation.ConstraintViolation;
-import javax.validation.MessageInterpolator;
-import javax.validation.TraversableResolver;
-import javax.validation.metadata.ConstraintDescriptor;
-
-import org.hibernate.validator.util.IdentitySet;
-
-/**
- * Context object keeping track of all important data for a top level {@link javax.validation.Validator#validate(Object, Class[])} },
- * {@link javax.validation.Validator#validateValue(Class, String, Object, Class[])}  } or {@link javax.validation.Validator#validateProperty(Object, String, Class[])}  call.
- * <p/>
- * we use this object to collect all failing constraints, but also to cache the caching traversable resolver for a full stack call.
- *
- * @author Hardy Ferentschik
- * @author Emmanuel Bernard
- */
-public class GlobalExecutionContext<T> {
-
-	/**
-	 * The root bean of the validation.
-	 */
-	private final T rootBean;
-
-	/**
-	 * The root bean class of the validation.
-	 */
-	private final Class<T> rootBeanClass;
-
-	/**
-	 * Maps a group to an identity set to keep track of already validated objects. We have to make sure
-	 * that each object gets only validated once per group and property path.
-	 */
-	private final Map<Class<?>, IdentitySet> processedObjects;
-
-	/**
-	 * Maps an object to a list of paths in which it has been invalidated.
-	 */
-	private final Map<Object, Set<PathImpl>> processedPaths;
-
-	/**
-	 * A list of all failing constraints so far.
-	 */
-	private final List<ConstraintViolation<T>> failingConstraintViolations;
-
-	/**
-	 * Flag indicating whether an object can only be validated once per group or once per group AND validation path.
-	 *
-	 * @todo Make this boolean a configurable item.
-	 */
-	private boolean allowOneValidationPerPath = true;
-
-	/**
-	 * The message resolver which should be used in this context.
-	 */
-	private final MessageInterpolator messageInterpolator;
-
-	/**
-	 * The constraint factory which should be used in this context.
-	 */
-	private final ConstraintValidatorFactory constraintValidatorFactory;
-
-	/**
-	 * Allows a JPA provider to decide whether a property should be validated.
-	 */
-	private final TraversableResolver traversableResolver;
-
-	public static <T> GlobalExecutionContext<T> getContextForValidate(T object, MessageInterpolator messageInterpolator, ConstraintValidatorFactory constraintValidatorFactory, TraversableResolver traversableResolver) {
-		@SuppressWarnings("unchecked")
-		Class<T> rootBeanClass = ( Class<T> ) object.getClass();
-		return new GlobalExecutionContext<T>(
-				rootBeanClass, object, messageInterpolator, constraintValidatorFactory, traversableResolver
-		);
-	}
-
-	public static <T> GlobalExecutionContext<T> getContextForValidateProperty(T rootBean, MessageInterpolator messageInterpolator, ConstraintValidatorFactory constraintValidatorFactory, TraversableResolver traversableResolver) {
-		@SuppressWarnings("unchecked")
-		Class<T> rootBeanClass = ( Class<T> ) rootBean.getClass();
-		return new GlobalExecutionContext<T>(
-				rootBeanClass, rootBean, messageInterpolator, constraintValidatorFactory, traversableResolver
-		);
-	}
-
-	public static <T> GlobalExecutionContext<T> getContextForValidateValue(Class<T> rootBeanClass, MessageInterpolator messageInterpolator, ConstraintValidatorFactory constraintValidatorFactory, TraversableResolver traversableResolver) {
-		return new GlobalExecutionContext<T>(
-				rootBeanClass,
-				null,
-				messageInterpolator,
-				constraintValidatorFactory,
-				traversableResolver
-		);
-	}
-
-	private GlobalExecutionContext(Class<T> rootBeanClass, T rootBean, MessageInterpolator messageInterpolator, ConstraintValidatorFactory constraintValidatorFactory, TraversableResolver traversableResolver) {
-		this.rootBean = rootBean;
-		this.rootBeanClass = rootBeanClass;
-		this.messageInterpolator = messageInterpolator;
-		this.constraintValidatorFactory = constraintValidatorFactory;
-		this.traversableResolver = traversableResolver;
-
-		processedObjects = new HashMap<Class<?>, IdentitySet>();
-		processedPaths = new IdentityHashMap<Object, Set<PathImpl>>();
-		failingConstraintViolations = new ArrayList<ConstraintViolation<T>>();
-	}
-
-	public T getRootBean() {
-		return rootBean;
-	}
-
-	public Class<T> getRootBeanClass() {
-		return rootBeanClass;
-	}
-
-	public TraversableResolver getTraversableResolver() {
-		return traversableResolver;
-	}
-
-	public MessageInterpolator getMessageInterpolator() {
-		return messageInterpolator;
-	}
-
-	public <U, V> ConstraintViolationImpl<T> createConstraintViolation(LocalExecutionContext<U, V> localContext, MessageAndPath messageAndPath, ConstraintDescriptor<?> descriptor) {
-		String messageTemplate = messageAndPath.getMessage();
-		String interpolatedMessage = messageInterpolator.interpolate(
-				messageTemplate,
-				new MessageInterpolatorContext( descriptor, localContext.getCurrentBean() )
-		);
-		return new ConstraintViolationImpl<T>(
-				messageTemplate,
-				interpolatedMessage,
-				getRootBeanClass(),
-				getRootBean(),
-				localContext.getCurrentBean(),
-				localContext.getCurrentValidatedValue(),
-				messageAndPath.getPath(),
-				descriptor,
-				localContext.getElementType()
-		);
-	}
-
-	public <U, V> List<ConstraintViolationImpl<T>> createConstraintViolations(LocalExecutionContext<U, V> localContext, ConstraintValidatorContextImpl constraintValidatorContext) {
-		List<ConstraintViolationImpl<T>> constraintViolations = new ArrayList<ConstraintViolationImpl<T>>();
-		for ( MessageAndPath messageAndPath : constraintValidatorContext.getMessageAndPathList() ) {
-			ConstraintViolationImpl<T> violation = createConstraintViolation(
-					localContext, messageAndPath, constraintValidatorContext.getConstraintDescriptor()
-			);
-			constraintViolations.add( violation );
-		}
-		return constraintViolations;
-	}
-
-	public ConstraintValidatorFactory getConstraintValidatorFactory() {
-		return constraintValidatorFactory;
-	}
-
-	public boolean isAlreadyValidated(Object value, Class<?> group, PathImpl path) {
-		boolean alreadyValidated;
-		alreadyValidated = isAlreadyValidatedForCurrentGroup( value, group );
-
-		if ( alreadyValidated && allowOneValidationPerPath ) {
-			alreadyValidated = isAlreadyValidatedForPath( value, path );
-		}
-		return alreadyValidated;
-	}
-
-	public void markProcessed(Object value, Class<?> group, PathImpl path) {
-		markProcessForCurrentGroup( value, group );
-		if ( allowOneValidationPerPath ) {
-			markProcessedForCurrentPath( value, path );
-		}
-	}
-
-	private void addConstraintFailure(ConstraintViolation<T> failingConstraintViolation) {
-		// NOTE: we are relying on the fact that ConstraintViolation.equals() is implemented correctly.
-		int i = failingConstraintViolations.indexOf( failingConstraintViolation );
-		if ( i == -1 ) {
-			failingConstraintViolations.add( failingConstraintViolation );
-		}
-	}
-
-	public void addConstraintFailures(List<ConstraintViolation<T>> failingConstraintViolations) {
-		for ( ConstraintViolation<T> violation : failingConstraintViolations ) {
-			addConstraintFailure( violation );
-		}
-	}
-
-	public List<ConstraintViolation<T>> getFailingConstraints() {
-		return failingConstraintViolations;
-	}
-
-	private boolean isAlreadyValidatedForPath(Object value, PathImpl path) {
-		Set<PathImpl> pathSet = processedPaths.get( value );
-		if ( pathSet == null ) {
-			return false;
-		}
-
-		for ( PathImpl p : pathSet ) {
-			if ( p.isRootPath() || path.isRootPath() || p.isSubPathOf( path ) || path.isSubPathOf( p ) ) {
-				return true;
-			}
-		}
-
-		return false;
-	}
-
-	private boolean isAlreadyValidatedForCurrentGroup(Object value, Class<?> group) {
-		final IdentitySet objectsProcessedInCurrentGroups = processedObjects.get( group );
-		return objectsProcessedInCurrentGroups != null && objectsProcessedInCurrentGroups.contains( value );
-	}
-
-	private void markProcessedForCurrentPath(Object value, PathImpl path) {
-		// hmm - not sure if the current definiton of Path and Node are consistent. Shouldn't a simple property
-		// of a entity have a parent node?
-		PathImpl parentPath = path.getPathWithoutLeafNode();
-		if ( parentPath == null ) {
-			parentPath = PathImpl.createNewPath( null );
-		}
-
-		if ( processedPaths.containsKey( value ) ) {
-			processedPaths.get( value ).add( parentPath );
-		}
-		else {
-			Set<PathImpl> set = new HashSet<PathImpl>();
-			set.add( parentPath );
-			processedPaths.put( value, set );
-		}
-	}
-
-
-	private void markProcessForCurrentGroup(Object value, Class<?> group) {
-		if ( processedObjects.containsKey( group ) ) {
-			processedObjects.get( group ).add( value );
-		}
-		else {
-			IdentitySet set = new IdentitySet();
-			set.add( value );
-			processedObjects.put( group, set );
-		}
-	}
-}

Deleted: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/LocalExecutionContext.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/LocalExecutionContext.java	2010-04-28 04:32:00 UTC (rev 19312)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/LocalExecutionContext.java	2010-04-28 11:05:26 UTC (rev 19313)
@@ -1,136 +0,0 @@
-// $Id$
-/*
-* 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.engine;
-
-import java.lang.annotation.ElementType;
-import javax.validation.groups.Default;
-
-/**
- * An instance of this class is used to collect all the relevant information for validating a single entity/bean.
- *
- * @author Hardy Ferentschik
- */
-public class LocalExecutionContext<T, V> {
-
-	/**
-	 * The current bean which gets validated. This is the bean hosting the constraints which get validated.
-	 */
-	private final T currentBean;
-
-	/**
-	 * The class of the current bean.
-	 */
-	private final Class<T> currentBeanType;
-
-	/**
-	 * The current property path we are validating.
-	 */
-	private PathImpl propertyPath;
-
-	/**
-	 * The current group we are validating.
-	 */
-	private Class<?> currentGroup;
-
-	/**
-	 * The value which gets currently evaluated.
-	 */
-	private V currentValue;
-
-	/**
-	 * The {@code ElementType} the constraint was defined on
-	 */
-	private ElementType elementType;
-
-	public static <T, V> LocalExecutionContext<T, V> getLocalExecutionContext(T value) {
-		@SuppressWarnings("unchecked")
-		Class<T> rootBeanClass = ( Class<T> ) value.getClass();
-		return new LocalExecutionContext<T, V>( value, rootBeanClass );
-	}
-
-	public static <T, V> LocalExecutionContext<T, V> getLocalExecutionContext(Class<T> type) {
-		return new LocalExecutionContext<T, V>( null, type );
-	}
-
-	public LocalExecutionContext(T currentBean, Class<T> currentBeanType) {
-		this.currentBean = currentBean;
-		this.currentBeanType = currentBeanType;
-	}
-
-	public PathImpl getPropertyPath() {
-		return propertyPath;
-	}
-
-	public Class<?> getCurrentGroup() {
-		return currentGroup;
-	}
-
-	public T getCurrentBean() {
-		return currentBean;
-	}
-
-	public Class<T> getCurrentBeanType() {
-		return currentBeanType;
-	}
-
-	public V getCurrentValidatedValue() {
-		return currentValue;
-	}
-
-	public void setPropertyPath(PathImpl propertyPath) {
-		this.propertyPath = propertyPath;
-	}
-
-	public void setCurrentGroup(Class<?> currentGroup) {
-		this.currentGroup = currentGroup;
-	}
-
-	public void setCurrentValidatedValue(V currentValue) {
-		this.currentValue = currentValue;
-	}
-
-	public void markCurrentPropertyAsIterable() {
-		propertyPath.getLeafNode().setInIterable( true );
-	}
-
-	public boolean validatingDefault() {
-		return getCurrentGroup() != null && getCurrentGroup().getName().equals( Default.class.getName() );
-	}
-
-	public ElementType getElementType() {
-		return elementType;
-	}
-
-	public void setElementType(ElementType elementType) {
-		this.elementType = elementType;
-	}
-
-	@Override
-	public String toString() {
-		final StringBuilder sb = new StringBuilder();
-		sb.append( "LocalExecutionContext" );
-		sb.append( "{currentBean=" ).append( currentBean );
-		sb.append( ", currentBeanType=" ).append( currentBeanType );
-		sb.append( ", propertyPath=" ).append( propertyPath );
-		sb.append( ", currentGroup=" ).append( currentGroup );
-		sb.append( ", currentValue=" ).append( currentValue );
-		sb.append( ", elementType=" ).append( elementType );
-		sb.append( '}' );
-		return sb.toString();
-	}
-}

Copied: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ValidationContext.java (from rev 19292, validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/GlobalExecutionContext.java)
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ValidationContext.java	                        (rev 0)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ValidationContext.java	2010-04-28 11:05:26 UTC (rev 19313)
@@ -0,0 +1,266 @@
+// $Id$
+/*
+* 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.engine;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.IdentityHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.validation.ConstraintValidatorFactory;
+import javax.validation.ConstraintViolation;
+import javax.validation.MessageInterpolator;
+import javax.validation.TraversableResolver;
+import javax.validation.metadata.ConstraintDescriptor;
+
+import org.hibernate.validator.util.IdentitySet;
+
+/**
+ * Context object keeping track of all important data for a top level {@link javax.validation.Validator#validate(Object, Class[])} },
+ * {@link javax.validation.Validator#validateValue(Class, String, Object, Class[])}  } or {@link javax.validation.Validator#validateProperty(Object, String, Class[])}  call.
+ * <p/>
+ * we use this object to collect all failing constraints, but also to cache the caching traversable resolver for a full stack call.
+ *
+ * @author Hardy Ferentschik
+ * @author Emmanuel Bernard
+ */
+public class ValidationContext<T> {
+
+	/**
+	 * The root bean of the validation.
+	 */
+	private final T rootBean;
+
+	/**
+	 * The root bean class of the validation.
+	 */
+	private final Class<T> rootBeanClass;
+
+	/**
+	 * Maps a group to an identity set to keep track of already validated objects. We have to make sure
+	 * that each object gets only validated once per group and property path.
+	 */
+	private final Map<Class<?>, IdentitySet> processedObjects;
+
+	/**
+	 * Maps an object to a list of paths in which it has been invalidated.
+	 */
+	private final Map<Object, Set<PathImpl>> processedPaths;
+
+	/**
+	 * A list of all failing constraints so far.
+	 */
+	private final List<ConstraintViolation<T>> failingConstraintViolations;
+
+	/**
+	 * Flag indicating whether an object can only be validated once per group or once per group AND validation path.
+	 *
+	 * @todo Make this boolean a configurable item.
+	 */
+	private boolean allowOneValidationPerPath = true;
+
+	/**
+	 * The message resolver which should be used in this context.
+	 */
+	private final MessageInterpolator messageInterpolator;
+
+	/**
+	 * The constraint factory which should be used in this context.
+	 */
+	private final ConstraintValidatorFactory constraintValidatorFactory;
+
+	/**
+	 * Allows a JPA provider to decide whether a property should be validated.
+	 */
+	private final TraversableResolver traversableResolver;
+
+	public static <T> ValidationContext<T> getContextForValidate(T object, MessageInterpolator messageInterpolator, ConstraintValidatorFactory constraintValidatorFactory, TraversableResolver traversableResolver) {
+		@SuppressWarnings("unchecked")
+		Class<T> rootBeanClass = ( Class<T> ) object.getClass();
+		return new ValidationContext<T>(
+				rootBeanClass, object, messageInterpolator, constraintValidatorFactory, traversableResolver
+		);
+	}
+
+	public static <T> ValidationContext<T> getContextForValidateProperty(T rootBean, MessageInterpolator messageInterpolator, ConstraintValidatorFactory constraintValidatorFactory, TraversableResolver traversableResolver) {
+		@SuppressWarnings("unchecked")
+		Class<T> rootBeanClass = ( Class<T> ) rootBean.getClass();
+		return new ValidationContext<T>(
+				rootBeanClass, rootBean, messageInterpolator, constraintValidatorFactory, traversableResolver
+		);
+	}
+
+	public static <T> ValidationContext<T> getContextForValidateValue(Class<T> rootBeanClass, MessageInterpolator messageInterpolator, ConstraintValidatorFactory constraintValidatorFactory, TraversableResolver traversableResolver) {
+		return new ValidationContext<T>(
+				rootBeanClass,
+				null,
+				messageInterpolator,
+				constraintValidatorFactory,
+				traversableResolver
+		);
+	}
+
+	private ValidationContext(Class<T> rootBeanClass, T rootBean, MessageInterpolator messageInterpolator, ConstraintValidatorFactory constraintValidatorFactory, TraversableResolver traversableResolver) {
+		this.rootBean = rootBean;
+		this.rootBeanClass = rootBeanClass;
+		this.messageInterpolator = messageInterpolator;
+		this.constraintValidatorFactory = constraintValidatorFactory;
+		this.traversableResolver = traversableResolver;
+
+		processedObjects = new HashMap<Class<?>, IdentitySet>();
+		processedPaths = new IdentityHashMap<Object, Set<PathImpl>>();
+		failingConstraintViolations = new ArrayList<ConstraintViolation<T>>();
+	}
+
+	public T getRootBean() {
+		return rootBean;
+	}
+
+	public Class<T> getRootBeanClass() {
+		return rootBeanClass;
+	}
+
+	public TraversableResolver getTraversableResolver() {
+		return traversableResolver;
+	}
+
+	public MessageInterpolator getMessageInterpolator() {
+		return messageInterpolator;
+	}
+
+	public <U, V> ConstraintViolationImpl<T> createConstraintViolation(ValueContext<U, V> localContext, MessageAndPath messageAndPath, ConstraintDescriptor<?> descriptor) {
+		String messageTemplate = messageAndPath.getMessage();
+		String interpolatedMessage = messageInterpolator.interpolate(
+				messageTemplate,
+				new MessageInterpolatorContext( descriptor, localContext.getCurrentBean() )
+		);
+		return new ConstraintViolationImpl<T>(
+				messageTemplate,
+				interpolatedMessage,
+				getRootBeanClass(),
+				getRootBean(),
+				localContext.getCurrentBean(),
+				localContext.getCurrentValidatedValue(),
+				messageAndPath.getPath(),
+				descriptor,
+				localContext.getElementType()
+		);
+	}
+
+	public <U, V> List<ConstraintViolationImpl<T>> createConstraintViolations(ValueContext<U, V> localContext, ConstraintValidatorContextImpl constraintValidatorContext) {
+		List<ConstraintViolationImpl<T>> constraintViolations = new ArrayList<ConstraintViolationImpl<T>>();
+		for ( MessageAndPath messageAndPath : constraintValidatorContext.getMessageAndPathList() ) {
+			ConstraintViolationImpl<T> violation = createConstraintViolation(
+					localContext, messageAndPath, constraintValidatorContext.getConstraintDescriptor()
+			);
+			constraintViolations.add( violation );
+		}
+		return constraintViolations;
+	}
+
+	public ConstraintValidatorFactory getConstraintValidatorFactory() {
+		return constraintValidatorFactory;
+	}
+
+	public boolean isAlreadyValidated(Object value, Class<?> group, PathImpl path) {
+		boolean alreadyValidated;
+		alreadyValidated = isAlreadyValidatedForCurrentGroup( value, group );
+
+		if ( alreadyValidated && allowOneValidationPerPath ) {
+			alreadyValidated = isAlreadyValidatedForPath( value, path );
+		}
+		return alreadyValidated;
+	}
+
+	public void markProcessed(Object value, Class<?> group, PathImpl path) {
+		markProcessForCurrentGroup( value, group );
+		if ( allowOneValidationPerPath ) {
+			markProcessedForCurrentPath( value, path );
+		}
+	}
+
+	private void addConstraintFailure(ConstraintViolation<T> failingConstraintViolation) {
+		// NOTE: we are relying on the fact that ConstraintViolation.equals() is implemented correctly.
+		int i = failingConstraintViolations.indexOf( failingConstraintViolation );
+		if ( i == -1 ) {
+			failingConstraintViolations.add( failingConstraintViolation );
+		}
+	}
+
+	public void addConstraintFailures(List<ConstraintViolation<T>> failingConstraintViolations) {
+		for ( ConstraintViolation<T> violation : failingConstraintViolations ) {
+			addConstraintFailure( violation );
+		}
+	}
+
+	public List<ConstraintViolation<T>> getFailingConstraints() {
+		return failingConstraintViolations;
+	}
+
+	private boolean isAlreadyValidatedForPath(Object value, PathImpl path) {
+		Set<PathImpl> pathSet = processedPaths.get( value );
+		if ( pathSet == null ) {
+			return false;
+		}
+
+		for ( PathImpl p : pathSet ) {
+			if ( p.isRootPath() || path.isRootPath() || p.isSubPathOf( path ) || path.isSubPathOf( p ) ) {
+				return true;
+			}
+		}
+
+		return false;
+	}
+
+	private boolean isAlreadyValidatedForCurrentGroup(Object value, Class<?> group) {
+		final IdentitySet objectsProcessedInCurrentGroups = processedObjects.get( group );
+		return objectsProcessedInCurrentGroups != null && objectsProcessedInCurrentGroups.contains( value );
+	}
+
+	private void markProcessedForCurrentPath(Object value, PathImpl path) {
+		// hmm - not sure if the current definiton of Path and Node are consistent. Shouldn't a simple property
+		// of a entity have a parent node?
+		PathImpl parentPath = path.getPathWithoutLeafNode();
+		if ( parentPath == null ) {
+			parentPath = PathImpl.createNewPath( null );
+		}
+
+		if ( processedPaths.containsKey( value ) ) {
+			processedPaths.get( value ).add( parentPath );
+		}
+		else {
+			Set<PathImpl> set = new HashSet<PathImpl>();
+			set.add( parentPath );
+			processedPaths.put( value, set );
+		}
+	}
+
+
+	private void markProcessForCurrentGroup(Object value, Class<?> group) {
+		if ( processedObjects.containsKey( group ) ) {
+			processedObjects.get( group ).add( value );
+		}
+		else {
+			IdentitySet set = new IdentitySet();
+			set.add( value );
+			processedObjects.put( group, set );
+		}
+	}
+}


Property changes on: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ValidationContext.java
___________________________________________________________________
Name: svn:keywords
   + Id

Modified: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ValidatorFactoryImpl.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ValidatorFactoryImpl.java	2010-04-28 04:32:00 UTC (rev 19312)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ValidatorFactoryImpl.java	2010-04-28 11:05:26 UTC (rev 19313)
@@ -21,7 +21,9 @@
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Member;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import javax.validation.ConstraintValidatorFactory;
 import javax.validation.MessageInterpolator;
@@ -110,28 +112,34 @@
 		for ( Class<?> clazz : processedClasses ) {
 			@SuppressWarnings("unchecked")
 			Class<T> beanClass = ( Class<T> ) clazz;
-			BeanMetaDataImpl<T> metaData = new BeanMetaDataImpl<T>(
-					beanClass, constraintHelper, annotationIgnores, beanMetaDataCache
-			);
 
 			List<Class<?>> classes = new ArrayList<Class<?>>();
 			ReflectionHelper.computeClassHierarchy( beanClass, classes );
+			Map<Class<?>, List<MetaConstraint<T, ?>>> constraints = new HashMap<Class<?>, List<MetaConstraint<T, ?>>>();
+			List<Member> cascadedMembers = new ArrayList<Member>();
 			for ( Class<?> classInHierarchy : classes ) {
 				if ( processedClasses.contains( classInHierarchy ) ) {
-					addXmlConfiguredConstraintToMetaData( mappingParser, beanClass, classInHierarchy, metaData );
+					addXmlConfiguredConstraints( mappingParser, beanClass, classInHierarchy, constraints );
+					addXmlCascadedMember( mappingParser, classInHierarchy, cascadedMembers );
 				}
 			}
 
-			if ( !mappingParser.getDefaultSequenceForClass( beanClass ).isEmpty() ) {
-				metaData.setDefaultGroupSequence( mappingParser.getDefaultSequenceForClass( beanClass ) );
-			}
+			BeanMetaDataImpl<T> metaData = new BeanMetaDataImpl<T>(
+					beanClass,
+					constraintHelper,
+					mappingParser.getDefaultSequenceForClass( beanClass ),
+					constraints,
+					cascadedMembers,
+					annotationIgnores,
+					beanMetaDataCache
+			);
 
 			beanMetaDataCache.addBeanMetaData( beanClass, metaData );
 		}
 	}
 
 	@SuppressWarnings("unchecked")
-	private <T, A extends Annotation> void addXmlConfiguredConstraintToMetaData(XmlMappingParser mappingParser, Class<T> rootClass, Class<?> hierarchyClass, BeanMetaDataImpl<T> metaData) {
+	private <T, A extends Annotation> void addXmlConfiguredConstraints(XmlMappingParser mappingParser, Class<T> rootClass, Class<?> hierarchyClass, Map<Class<?>, List<MetaConstraint<T, ?>>> constraints) {
 		for ( MetaConstraint<?, ? extends Annotation> constraint : mappingParser.getConstraintsForClass( hierarchyClass ) ) {
 			ConstraintOrigin definedIn = definedIn( rootClass, hierarchyClass );
 			ConstraintDescriptorImpl<A> descriptor = new ConstraintDescriptorImpl<A>(
@@ -143,11 +151,18 @@
 			MetaConstraint<T, A> newMetaConstraint = new MetaConstraint<T, A>(
 					rootClass, constraint.getMember(), descriptor
 			);
-			metaData.addMetaConstraint( hierarchyClass, newMetaConstraint );
+			List<MetaConstraint<T, ?>> constraintList = constraints.get( hierarchyClass );
+			if ( constraintList == null ) {
+				constraintList = new ArrayList<MetaConstraint<T, ?>>();
+				constraints.put( hierarchyClass, constraintList );
+			}
+			constraintList.add( newMetaConstraint );
 		}
+	}
 
+	private void addXmlCascadedMember(XmlMappingParser mappingParser, Class<?> hierarchyClass, List<Member> cascadedMembers) {
 		for ( Member m : mappingParser.getCascadedMembersForClass( hierarchyClass ) ) {
-			metaData.addCascadedMember( m );
+			cascadedMembers.add( m );
 		}
 	}
 

Modified: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ValidatorImpl.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ValidatorImpl.java	2010-04-28 04:32:00 UTC (rev 19312)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ValidatorImpl.java	2010-04-28 11:05:26 UTC (rev 19313)
@@ -105,14 +105,14 @@
 		groupChainGenerator = new GroupChainGenerator();
 	}
 
-	public <T> Set<ConstraintViolation<T>> validate(T object, Class<?>... groups) {
+	public final <T> Set<ConstraintViolation<T>> validate(T object, Class<?>... groups) {
 		if ( object == null ) {
 			throw new IllegalArgumentException( "Validation of a null object" );
 		}
 
 		GroupChain groupChain = determineGroupExecutionOrder( groups );
 
-		GlobalExecutionContext<T> context = GlobalExecutionContext.getContextForValidate(
+		ValidationContext<T> context = ValidationContext.getContextForValidate(
 				object, messageInterpolator, constraintValidatorFactory, getCachingTraversableResolver()
 		);
 
@@ -120,7 +120,7 @@
 		return new HashSet<ConstraintViolation<T>>( list );
 	}
 
-	public <T> Set<ConstraintViolation<T>> validateProperty(T object, String propertyName, Class<?>... groups) {
+	public final <T> Set<ConstraintViolation<T>> validateProperty(T object, String propertyName, Class<?>... groups) {
 		if ( object == null ) {
 			throw new IllegalArgumentException( "Validated object cannot be null." );
 		}
@@ -134,7 +134,7 @@
 		return new HashSet<ConstraintViolation<T>>( failingConstraintViolations );
 	}
 
-	public <T> Set<ConstraintViolation<T>> validateValue(Class<T> beanType, String propertyName, Object value, Class<?>... groups) {
+	public final <T> Set<ConstraintViolation<T>> validateValue(Class<T> beanType, String propertyName, Object value, Class<?>... groups) {
 		if ( beanType == null ) {
 			throw new IllegalArgumentException( "The bean type cannot be null." );
 		}
@@ -149,14 +149,11 @@
 		return new HashSet<ConstraintViolation<T>>( failingConstraintViolations );
 	}
 
-	/**
-	 * {@inheritDoc}
-	 */
-	public BeanDescriptor getConstraintsForClass(Class<?> clazz) {
+	public final BeanDescriptor getConstraintsForClass(Class<?> clazz) {
 		return getBeanMetaData( clazz ).getBeanDescriptor();
 	}
 
-	public <T> T unwrap(Class<T> type) {
+	public final <T> T unwrap(Class<T> type) {
 		throw new ValidationException( "Type " + type + " not supported" );
 	}
 
@@ -183,7 +180,7 @@
 	 * Validates the given object using the available context information.
 	 *
 	 * @param value The value to validate.
-	 * @param context Global context. Used amongst others to collect all failing constraints.
+	 * @param context the validation context.
 	 * @param groupChain Contains the information which and in which order groups have to be executed
 	 * @param path The current path of the validation.
 	 * @param <T> The root bean type.
@@ -191,32 +188,32 @@
 	 *
 	 * @return List of constraint violations or the empty set if there were no violations.
 	 */
-	private <T, U, V> List<ConstraintViolation<T>> validateInContext(U value, GlobalExecutionContext<T> context, GroupChain groupChain, PathImpl path) {
+	private <T, U, V> List<ConstraintViolation<T>> validateInContext(U value, ValidationContext<T> context, GroupChain groupChain, PathImpl path) {
 		if ( value == null ) {
 			return Collections.emptyList();
 		}
 
 		path = PathImpl.createShallowCopy( path );
-		LocalExecutionContext<U, V> localExecutionContext = LocalExecutionContext.getLocalExecutionContext( value );
+		ValueContext<U, V> valueContext = ValueContext.getLocalExecutionContext( value );
 
-		BeanMetaData<U> beanMetaData = getBeanMetaData( localExecutionContext.getCurrentBeanType() );
+		BeanMetaData<U> beanMetaData = getBeanMetaData( valueContext.getCurrentBeanType() );
 		if ( beanMetaData.defaultGroupSequenceIsRedefined() ) {
 			groupChain.assertDefaultGroupSequenceIsExpandable( beanMetaData.getDefaultGroupSequence() );
 		}
 
-		// process first single groups. For these we can skip some object traversal, by first running all validations on the current bean
+		// 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<Group> groupIterator = groupChain.getGroupIterator();
 		while ( groupIterator.hasNext() ) {
 			Group group = groupIterator.next();
-			localExecutionContext.setCurrentGroup( group.getGroup() );
-			validateConstraintsForCurrentGroup( context, localExecutionContext, path );
+			valueContext.setCurrentGroup( group.getGroup() );
+			validateConstraintsForCurrentGroup( context, valueContext, path );
 		}
 		groupIterator = groupChain.getGroupIterator();
 		while ( groupIterator.hasNext() ) {
 			Group group = groupIterator.next();
-			localExecutionContext.setCurrentGroup( group.getGroup() );
-			validateCascadedConstraints( context, localExecutionContext, path );
+			valueContext.setCurrentGroup( group.getGroup() );
+			validateCascadedConstraints( context, valueContext, path );
 		}
 
 		// now we process sequences. For sequences I have to traverse the object graph since I have to stop processing when an error occurs.
@@ -225,10 +222,10 @@
 			List<Group> sequence = sequenceIterator.next();
 			for ( Group group : sequence ) {
 				int numberOfViolations = context.getFailingConstraints().size();
-				localExecutionContext.setCurrentGroup( group.getGroup() );
+				valueContext.setCurrentGroup( group.getGroup() );
 
-				validateConstraintsForCurrentGroup( context, localExecutionContext, path );
-				validateCascadedConstraints( context, localExecutionContext, path );
+				validateConstraintsForCurrentGroup( context, valueContext, path );
+				validateCascadedConstraints( context, valueContext, path );
 
 				if ( context.getFailingConstraints().size() > numberOfViolations ) {
 					break;
@@ -238,33 +235,31 @@
 		return context.getFailingConstraints();
 	}
 
-	private <T, U, V> void validateConstraintsForCurrentGroup(GlobalExecutionContext<T> globalExecutionContext, LocalExecutionContext<U, V> localExecutionContext, PathImpl path) {
-		BeanMetaData<U> beanMetaData = getBeanMetaData( localExecutionContext.getCurrentBeanType() );
-		boolean validatingDefault = localExecutionContext.validatingDefault();
+	private <T, U, V> void validateConstraintsForCurrentGroup(ValidationContext<T> validationContext, ValueContext<U, V> valueContext, PathImpl path) {
+		BeanMetaData<U> beanMetaData = getBeanMetaData( valueContext.getCurrentBeanType() );
+		boolean validatingDefault = valueContext.validatingDefault();
 		boolean validatedBeanRedefinesDefault = beanMetaData.defaultGroupSequenceIsRedefined();
 
 		// if we are not validating the default group there is nothing special to consider
 		if ( !validatingDefault ) {
-			validateConstraintsForNonDefaultGroup( globalExecutionContext, localExecutionContext, path );
+			validateConstraintsForNonDefaultGroup( validationContext, valueContext, path );
 			return;
 		}
 
-		// if we are validating the default group we have to distinguish between the case where the main entity type redefines the default group and
-		// where not
+		// if we are validating the default group we have to distinguish between the case where the main entity type redefines the default group and where not
 		if ( validatedBeanRedefinesDefault ) {
 			validateConstraintsForRedefinedDefaultGroupOnMainEntity(
-					globalExecutionContext, localExecutionContext, path, beanMetaData
+					validationContext, valueContext, path, beanMetaData
 			);
 		}
 		else {
 			validateConstraintsForRedefinedDefaultGroup(
-					globalExecutionContext, localExecutionContext, path, beanMetaData
+					validationContext, valueContext, path, beanMetaData
 			);
 		}
 	}
 
-	private <T, U, V> void validateConstraintsForRedefinedDefaultGroup(GlobalExecutionContext<T> globalExecutionContext, LocalExecutionContext<U, V> localExecutionContext, PathImpl path, BeanMetaData<U> beanMetaData) {
-		// in the case where the main entity does not redefine the default group we have to check whether the entity which defines the constraint does
+	private <T, U, V> void validateConstraintsForRedefinedDefaultGroup(ValidationContext<T> validationContext, ValueContext<U, V> valueContext, PathImpl path, BeanMetaData<U> beanMetaData) {
 		for ( Map.Entry<Class<?>, List<MetaConstraint<U, ? extends Annotation>>> entry : beanMetaData.getMetaConstraintsAsMap()
 				.entrySet() ) {
 			Class<?> hostingBeanClass = entry.getKey();
@@ -272,11 +267,11 @@
 
 			List<Class<?>> defaultGroupSequence = getBeanMetaData( hostingBeanClass ).getDefaultGroupSequence();
 			for ( Class<?> defaultSequenceMember : defaultGroupSequence ) {
-				localExecutionContext.setCurrentGroup( defaultSequenceMember );
+				valueContext.setCurrentGroup( defaultSequenceMember );
 				boolean validationSuccessful = true;
 				for ( MetaConstraint<U, ? extends Annotation> metaConstraint : constraints ) {
 					boolean tmp = validateConstraint(
-							globalExecutionContext, localExecutionContext, metaConstraint, path
+							validationContext, valueContext, metaConstraint, path
 					);
 					validationSuccessful = validationSuccessful && tmp;
 				}
@@ -287,16 +282,14 @@
 		}
 	}
 
-	private <T, U, V> void validateConstraintsForRedefinedDefaultGroupOnMainEntity(GlobalExecutionContext<T> globalExecutionContext, LocalExecutionContext<U, V> localExecutionContext, PathImpl path, BeanMetaData<U> beanMetaData) {
-		// in the case where the main entity redefines the default group we can iterate over all constraints independent of the bean they are
-		// defined in. The redefined group sequence applies for all constraints.
+	private <T, U, V> void validateConstraintsForRedefinedDefaultGroupOnMainEntity(ValidationContext<T> validationContext, ValueContext<U, V> valueContext, PathImpl path, BeanMetaData<U> beanMetaData) {
 		List<Class<?>> defaultGroupSequence = beanMetaData.getDefaultGroupSequence();
 		for ( Class<?> defaultSequenceMember : defaultGroupSequence ) {
-			localExecutionContext.setCurrentGroup( defaultSequenceMember );
+			valueContext.setCurrentGroup( defaultSequenceMember );
 			boolean validationSuccessful = true;
 			for ( MetaConstraint<U, ? extends Annotation> metaConstraint : beanMetaData.getMetaConstraintsAsList() ) {
 				boolean tmp = validateConstraint(
-						globalExecutionContext, localExecutionContext, metaConstraint, path
+						validationContext, valueContext, metaConstraint, path
 				);
 				validationSuccessful = validationSuccessful && tmp;
 			}
@@ -306,14 +299,14 @@
 		}
 	}
 
-	private <T, U, V> void validateConstraintsForNonDefaultGroup(GlobalExecutionContext<T> globalExecutionContext, LocalExecutionContext<U, V> localExecutionContext, PathImpl path) {
-		BeanMetaData<U> beanMetaData = getBeanMetaData( localExecutionContext.getCurrentBeanType() );
+	private <T, U, V> void validateConstraintsForNonDefaultGroup(ValidationContext<T> validationContext, ValueContext<U, V> valueContext, PathImpl path) {
+		BeanMetaData<U> beanMetaData = getBeanMetaData( valueContext.getCurrentBeanType() );
 		for ( MetaConstraint<U, ? extends Annotation> metaConstraint : beanMetaData.getMetaConstraintsAsList() ) {
-			validateConstraint( globalExecutionContext, localExecutionContext, metaConstraint, path );
+			validateConstraint( validationContext, valueContext, metaConstraint, path );
 		}
 	}
 
-	private <T, U, V> boolean validateConstraint(GlobalExecutionContext<T> globalExecutionContext, LocalExecutionContext<U, V> localExecutionContext, MetaConstraint<U, ?> metaConstraint, PathImpl path) {
+	private <T, U, V> boolean validateConstraint(ValidationContext<T> validationContext, ValueContext<U, V> valueContext, MetaConstraint<U, ?> metaConstraint, PathImpl path) {
 		boolean validationSuccessful = true;
 		PathImpl newPath;
 
@@ -327,16 +320,16 @@
 			}
 		}
 
-		localExecutionContext.setPropertyPath( newPath );
-		if ( isValidationRequired( globalExecutionContext, localExecutionContext, metaConstraint ) ) {
-			Object valueToValidate = metaConstraint.getValue( localExecutionContext.getCurrentBean() );
-			localExecutionContext.setCurrentValidatedValue( ( V ) valueToValidate );
-			validationSuccessful = metaConstraint.validateConstraint( globalExecutionContext, localExecutionContext );
+		valueContext.setPropertyPath( newPath );
+		if ( isValidationRequired( validationContext, valueContext, metaConstraint ) ) {
+			Object valueToValidate = metaConstraint.getValue( valueContext.getCurrentBean() );
+			valueContext.setCurrentValidatedValue( ( V ) valueToValidate );
+			validationSuccessful = metaConstraint.validateConstraint( validationContext, valueContext );
 		}
-		globalExecutionContext.markProcessed(
-				localExecutionContext.getCurrentBean(),
-				localExecutionContext.getCurrentGroup(),
-				localExecutionContext.getPropertyPath()
+		validationContext.markProcessed(
+				valueContext.getCurrentBean(),
+				valueContext.getCurrentGroup(),
+				valueContext.getPropertyPath()
 		);
 
 		return validationSuccessful;
@@ -346,12 +339,12 @@
 	 * 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.
 	 *
-	 * @param globalExecutionContext The execution context
-	 * @param localExecutionContext Collected information for single validation
+	 * @param validationContext The execution context
+	 * @param valueContext Collected information for single validation
 	 * @param path The current path of the validation.
 	 */
-	private <T, U, V> void validateCascadedConstraints(GlobalExecutionContext<T> globalExecutionContext, LocalExecutionContext<U, V> localExecutionContext, PathImpl path) {
-		List<Member> cascadedMembers = getBeanMetaData( localExecutionContext.getCurrentBeanType() )
+	private <T, U, V> void validateCascadedConstraints(ValidationContext<T> validationContext, ValueContext<U, V> valueContext, PathImpl path) {
+		List<Member> cascadedMembers = getBeanMetaData( valueContext.getCurrentBeanType() )
 				.getCascadedMembers();
 		for ( Member member : cascadedMembers ) {
 			Type type = ReflectionHelper.typeOf( member );
@@ -363,18 +356,18 @@
 				newPath = PathImpl.createShallowCopy( path );
 				newPath.addNode( new NodeImpl( ReflectionHelper.getPropertyName( member ) ) );
 			}
-			localExecutionContext.setPropertyPath( newPath );
-			if ( isCascadeRequired( globalExecutionContext, localExecutionContext, member ) ) {
-				Object value = ReflectionHelper.getValue( member, localExecutionContext.getCurrentBean() );
+			valueContext.setPropertyPath( newPath );
+			if ( isCascadeRequired( validationContext, valueContext, member ) ) {
+				Object value = ReflectionHelper.getValue( member, valueContext.getCurrentBean() );
 				if ( value != null ) {
-					Iterator<?> iter = createIteratorForCascadedValue( localExecutionContext, type, value );
+					Iterator<?> iter = createIteratorForCascadedValue( valueContext, type, value );
 					boolean isIndexable = isIndexable( type );
 					validateCascadedConstraint(
-							globalExecutionContext,
+							validationContext,
 							iter,
 							isIndexable,
-							localExecutionContext.getCurrentGroup(),
-							localExecutionContext.getPropertyPath()
+							valueContext.getCurrentGroup(),
+							valueContext.getPropertyPath()
 					);
 				}
 			}
@@ -391,7 +384,7 @@
 	 *
 	 * @return An iterator over the value of a cascaded property.
 	 */
-	private <U, V> Iterator<?> createIteratorForCascadedValue(LocalExecutionContext<U, V> context, Type type, Object value) {
+	private <U, V> Iterator<?> createIteratorForCascadedValue(ValueContext<U, V> context, Type type, Object value) {
 		Iterator<?> iter;
 		if ( ReflectionHelper.isIterable( type ) ) {
 			iter = ( ( Iterable<?> ) value ).iterator();
@@ -438,7 +431,7 @@
 	}
 
 	@SuppressWarnings("RedundantArrayCreation")
-	private <T> void validateCascadedConstraint(GlobalExecutionContext<T> context, Iterator<?> iter, boolean isIndexable, Class<?> currentGroup, PathImpl currentPath) {
+	private <T> void validateCascadedConstraint(ValidationContext<T> context, Iterator<?> iter, boolean isIndexable, Class<?> currentGroup, PathImpl currentPath) {
 		Object value;
 		Integer index;
 		Object mapKey;
@@ -548,13 +541,13 @@
 
 		for ( Class<?> groupClass : groupList ) {
 			for ( MetaConstraint<T, ?> metaConstraint : metaConstraints ) {
-				GlobalExecutionContext<T> context = GlobalExecutionContext.getContextForValidateProperty(
+				ValidationContext<T> context = ValidationContext.getContextForValidateProperty(
 						object,
 						messageInterpolator,
 						constraintValidatorFactory,
 						cachedTraversableResolver
 				);
-				LocalExecutionContext<U, V> localContext = LocalExecutionContext.getLocalExecutionContext(
+				ValueContext<U, V> localContext = ValueContext.getLocalExecutionContext(
 						hostingBeanInstance
 				);
 				localContext.setPropertyPath( path );
@@ -644,10 +637,10 @@
 
 		for ( Class<?> groupClass : groupList ) {
 			for ( MetaConstraint<U, ?> metaConstraint : metaConstraints ) {
-				GlobalExecutionContext<U> context = GlobalExecutionContext.getContextForValidateValue(
+				ValidationContext<U> context = ValidationContext.getContextForValidateValue(
 						beanType, messageInterpolator, constraintValidatorFactory, cachedTraversableResolver
 				);
-				LocalExecutionContext<U, V> localContext = LocalExecutionContext.getLocalExecutionContext( beanType );
+				ValueContext<U, V> localContext = ValueContext.getLocalExecutionContext( beanType );
 				localContext.setPropertyPath( path );
 				localContext.setCurrentGroup( groupClass );
 				localContext.setCurrentValidatedValue( value );
@@ -748,7 +741,7 @@
 		return new SingleThreadCachedTraversableResolver( traversableResolver );
 	}
 
-	private boolean isValidationRequired(GlobalExecutionContext globalContext, LocalExecutionContext localContext, MetaConstraint metaConstraint) {
+	private boolean isValidationRequired(ValidationContext validationContext, ValueContext localContext, MetaConstraint metaConstraint) {
 		if ( !metaConstraint.getGroupList().contains( localContext.getCurrentGroup() ) ) {
 			return false;
 		}
@@ -761,10 +754,10 @@
 		}
 
 		try {
-			isReachable = globalContext.getTraversableResolver().isReachable(
+			isReachable = validationContext.getTraversableResolver().isReachable(
 					localContext.getCurrentBean(),
 					localContext.getPropertyPath().getLeafNode(),
-					globalContext.getRootBeanClass(),
+					validationContext.getRootBeanClass(),
 					pathToObject,
 					metaConstraint.getElementType()
 			);
@@ -776,7 +769,7 @@
 		return isReachable;
 	}
 
-	private boolean isCascadeRequired(GlobalExecutionContext globalContext, LocalExecutionContext localContext, Member member) {
+	private boolean isCascadeRequired(ValidationContext validationContext, ValueContext localContext, Member member) {
 		final ElementType type = member instanceof Field ? ElementType.FIELD : ElementType.METHOD;
 		boolean isReachable;
 		boolean isCascadable;
@@ -787,10 +780,10 @@
 		}
 
 		try {
-			isReachable = globalContext.getTraversableResolver().isReachable(
+			isReachable = validationContext.getTraversableResolver().isReachable(
 					localContext.getCurrentBean(),
 					localContext.getPropertyPath().getLeafNode(),
-					globalContext.getRootBeanClass(),
+					validationContext.getRootBeanClass(),
 					pathToObject,
 					type
 			);
@@ -800,10 +793,10 @@
 		}
 
 		try {
-			isCascadable = globalContext.getTraversableResolver().isCascadable(
+			isCascadable = validationContext.getTraversableResolver().isCascadable(
 					localContext.getCurrentBean(),
 					localContext.getPropertyPath().getLeafNode(),
-					globalContext.getRootBeanClass(),
+					validationContext.getRootBeanClass(),
 					pathToObject,
 					type
 			);

Copied: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ValueContext.java (from rev 19292, validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/LocalExecutionContext.java)
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ValueContext.java	                        (rev 0)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ValueContext.java	2010-04-28 11:05:26 UTC (rev 19313)
@@ -0,0 +1,136 @@
+// $Id$
+/*
+* 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.engine;
+
+import java.lang.annotation.ElementType;
+import javax.validation.groups.Default;
+
+/**
+ * An instance of this class is used to collect all the relevant information for validating a single entity/bean.
+ *
+ * @author Hardy Ferentschik
+ */
+public class ValueContext<T, V> {
+
+	/**
+	 * The current bean which gets validated. This is the bean hosting the constraints which get validated.
+	 */
+	private final T currentBean;
+
+	/**
+	 * The class of the current bean.
+	 */
+	private final Class<T> currentBeanType;
+
+	/**
+	 * The current property path we are validating.
+	 */
+	private PathImpl propertyPath;
+
+	/**
+	 * The current group we are validating.
+	 */
+	private Class<?> currentGroup;
+
+	/**
+	 * The value which gets currently evaluated.
+	 */
+	private V currentValue;
+
+	/**
+	 * The {@code ElementType} the constraint was defined on
+	 */
+	private ElementType elementType;
+
+	public static <T, V> ValueContext<T, V> getLocalExecutionContext(T value) {
+		@SuppressWarnings("unchecked")
+		Class<T> rootBeanClass = ( Class<T> ) value.getClass();
+		return new ValueContext<T, V>( value, rootBeanClass );
+	}
+
+	public static <T, V> ValueContext<T, V> getLocalExecutionContext(Class<T> type) {
+		return new ValueContext<T, V>( null, type );
+	}
+
+	public ValueContext(T currentBean, Class<T> currentBeanType) {
+		this.currentBean = currentBean;
+		this.currentBeanType = currentBeanType;
+	}
+
+	public PathImpl getPropertyPath() {
+		return propertyPath;
+	}
+
+	public Class<?> getCurrentGroup() {
+		return currentGroup;
+	}
+
+	public T getCurrentBean() {
+		return currentBean;
+	}
+
+	public Class<T> getCurrentBeanType() {
+		return currentBeanType;
+	}
+
+	public V getCurrentValidatedValue() {
+		return currentValue;
+	}
+
+	public void setPropertyPath(PathImpl propertyPath) {
+		this.propertyPath = propertyPath;
+	}
+
+	public void setCurrentGroup(Class<?> currentGroup) {
+		this.currentGroup = currentGroup;
+	}
+
+	public void setCurrentValidatedValue(V currentValue) {
+		this.currentValue = currentValue;
+	}
+
+	public void markCurrentPropertyAsIterable() {
+		propertyPath.getLeafNode().setInIterable( true );
+	}
+
+	public boolean validatingDefault() {
+		return getCurrentGroup() != null && getCurrentGroup().getName().equals( Default.class.getName() );
+	}
+
+	public ElementType getElementType() {
+		return elementType;
+	}
+
+	public void setElementType(ElementType elementType) {
+		this.elementType = elementType;
+	}
+
+	@Override
+	public String toString() {
+		final StringBuilder sb = new StringBuilder();
+		sb.append( "ValueContext" );
+		sb.append( "{currentBean=" ).append( currentBean );
+		sb.append( ", currentBeanType=" ).append( currentBeanType );
+		sb.append( ", propertyPath=" ).append( propertyPath );
+		sb.append( ", currentGroup=" ).append( currentGroup );
+		sb.append( ", currentValue=" ).append( currentValue );
+		sb.append( ", elementType=" ).append( elementType );
+		sb.append( '}' );
+		return sb.toString();
+	}
+}


Property changes on: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ValueContext.java
___________________________________________________________________
Name: svn:keywords
   + Id

Modified: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/metadata/BeanMetaDataImpl.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/metadata/BeanMetaDataImpl.java	2010-04-28 04:32:00 UTC (rev 19312)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/metadata/BeanMetaDataImpl.java	2010-04-28 11:05:26 UTC (rev 19313)
@@ -55,9 +55,8 @@
  *
  * @author Hardy Ferentschik
  */
+public final class BeanMetaDataImpl<T> implements BeanMetaData<T> {
 
-public class BeanMetaDataImpl<T> implements BeanMetaData<T> {
-
 	private static final Logger log = LoggerFactory.make();
 
 	/**
@@ -87,7 +86,7 @@
 	private Map<String, PropertyDescriptor> propertyDescriptors = new HashMap<String, PropertyDescriptor>();
 
 	/**
-	 * Maps group sequences to the list of group/sequences.
+	 * The default groups sequence for this bean class.
 	 */
 	private List<Class<?>> defaultGroupSequence = new ArrayList<Class<?>>();
 
@@ -99,22 +98,43 @@
 	/**
 	 * A list of all property names in the class (constraint and un-constraint).
 	 */
-	// Used to avoid ReflectionHelper#containsMembe which is slow
+	// Used to avoid ReflectionHelper#containsMember which is slow
 	private final Set<String> propertyNames = new HashSet<String>( 30 );
 
 	public BeanMetaDataImpl(Class<T> beanClass, ConstraintHelper constraintHelper, BeanMetaDataCache beanMetaDataCache) {
 		this(
 				beanClass,
 				constraintHelper,
+				new ArrayList<Class<?>>(),
+				new HashMap<Class<?>, List<MetaConstraint<T, ?>>>(),
+				new ArrayList<Member>(),
 				new AnnotationIgnores(),
 				beanMetaDataCache
 		);
 	}
 
-	public BeanMetaDataImpl(Class<T> beanClass, ConstraintHelper constraintHelper, AnnotationIgnores annotationIgnores, BeanMetaDataCache beanMetaDataCache) {
+	public BeanMetaDataImpl(Class<T> beanClass,
+							ConstraintHelper constraintHelper,
+							List<Class<?>> defaultGroupSequence,
+							Map<Class<?>, List<MetaConstraint<T, ?>>> xmlConfiguredConstraints,
+							List<Member> xmlConfiguredMember,
+							AnnotationIgnores annotationIgnores,
+							BeanMetaDataCache beanMetaDataCache) {
 		this.beanClass = beanClass;
 		this.constraintHelper = constraintHelper;
 		createMetaData( annotationIgnores, beanMetaDataCache );
+		if ( !defaultGroupSequence.isEmpty() ) {
+			setDefaultGroupSequence( defaultGroupSequence );
+		}
+		for ( Map.Entry<Class<?>, List<MetaConstraint<T, ?>>> entry : xmlConfiguredConstraints.entrySet() ) {
+			Class<?> clazz = entry.getKey();
+			for(MetaConstraint<T,?> constraint : entry.getValue()) {
+				addMetaConstraint( clazz, constraint );
+			}
+		}
+		for ( Member member : xmlConfiguredMember ) {
+			addCascadedMember( member );
+		}
 	}
 
 	public Class<T> getBeanClass() {
@@ -141,40 +161,6 @@
 		return Collections.unmodifiableList( constraintList );
 	}
 
-	public void addMetaConstraint(Class<?> clazz, MetaConstraint<T, ? extends Annotation> metaConstraint) {
-		// first we add the meta constraint to our meta constraint map
-		List<MetaConstraint<T, ? extends Annotation>> constraintList;
-		if ( !metaConstraints.containsKey( clazz ) ) {
-			constraintList = new ArrayList<MetaConstraint<T, ? extends Annotation>>();
-			metaConstraints.put( clazz, constraintList );
-		}
-		else {
-			constraintList = metaConstraints.get( clazz );
-		}
-		constraintList.add( metaConstraint );
-
-		// but we also have to update the descriptors exposing the BV metadata API
-		if ( metaConstraint.getElementType() == ElementType.TYPE ) {
-			beanDescriptor.addConstraintDescriptor( metaConstraint.getDescriptor() );
-		}
-		else {
-			PropertyDescriptorImpl propertyDescriptor = ( PropertyDescriptorImpl ) propertyDescriptors.get(
-					metaConstraint.getPropertyName()
-			);
-			if ( propertyDescriptor == null ) {
-				Member member = metaConstraint.getMember();
-				propertyDescriptor = addPropertyDescriptorForMember( member, isValidAnnotationPresent( member ) );
-			}
-			propertyDescriptor.addConstraintDescriptor( metaConstraint.getDescriptor() );
-		}
-	}
-
-	public void addCascadedMember(Member member) {
-		setAccessibility( member );
-		cascadedMembers.add( member );
-		addPropertyDescriptorForMember( member, true );
-	}
-
 	public PropertyDescriptor getPropertyDescriptor(String property) {
 		return propertyDescriptors.get( property );
 	}
@@ -191,7 +177,11 @@
 		return defaultGroupSequence.size() > 1;
 	}
 
-	public void setDefaultGroupSequence(List<Class<?>> groupSequence) {
+	public Set<PropertyDescriptor> getConstrainedProperties() {
+		return Collections.unmodifiableSet( new HashSet<PropertyDescriptor>( propertyDescriptors.values() ) );
+	}
+
+	private void setDefaultGroupSequence(List<Class<?>> groupSequence) {
 		defaultGroupSequence = new ArrayList<Class<?>>();
 		boolean groupSequenceContainsDefault = false;
 		for ( Class<?> group : groupSequence ) {
@@ -218,10 +208,40 @@
 		}
 	}
 
-	public Set<PropertyDescriptor> getConstrainedProperties() {
-		return Collections.unmodifiableSet( new HashSet<PropertyDescriptor>( propertyDescriptors.values() ) );
+	private void addMetaConstraint(Class<?> clazz, MetaConstraint<T, ? extends Annotation> metaConstraint) {
+		// first we add the meta constraint to our meta constraint map
+		List<MetaConstraint<T, ? extends Annotation>> constraintList;
+		if ( !metaConstraints.containsKey( clazz ) ) {
+			constraintList = new ArrayList<MetaConstraint<T, ? extends Annotation>>();
+			metaConstraints.put( clazz, constraintList );
+		}
+		else {
+			constraintList = metaConstraints.get( clazz );
+		}
+		constraintList.add( metaConstraint );
+
+		// but we also have to update the descriptors exposing the BV metadata API
+		if ( metaConstraint.getElementType() == ElementType.TYPE ) {
+			beanDescriptor.addConstraintDescriptor( metaConstraint.getDescriptor() );
+		}
+		else {
+			PropertyDescriptorImpl propertyDescriptor = ( PropertyDescriptorImpl ) propertyDescriptors.get(
+					metaConstraint.getPropertyName()
+			);
+			if ( propertyDescriptor == null ) {
+				Member member = metaConstraint.getMember();
+				propertyDescriptor = addPropertyDescriptorForMember( member, isValidAnnotationPresent( member ) );
+			}
+			propertyDescriptor.addConstraintDescriptor( metaConstraint.getDescriptor() );
+		}
 	}
 
+	private void addCascadedMember(Member member) {
+		setAccessibility( member );
+		cascadedMembers.add( member );
+		addPropertyDescriptorForMember( member, true );
+	}
+
 	/**
 	 * Create bean descriptor, find all classes/subclasses/interfaces which have to be taken in consideration
 	 * for this validator and create meta data.
@@ -258,6 +278,7 @@
 		else {
 			groupSequence.addAll( Arrays.asList( groupSequenceAnnotation.value() ) );
 		}
+
 		setDefaultGroupSequence( groupSequence );
 	}
 

Modified: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/metadata/MetaConstraint.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/metadata/MetaConstraint.java	2010-04-28 04:32:00 UTC (rev 19312)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/metadata/MetaConstraint.java	2010-04-28 11:05:26 UTC (rev 19313)
@@ -29,8 +29,8 @@
 import javax.validation.ValidationException;
 
 import org.hibernate.validator.engine.ConstraintTree;
-import org.hibernate.validator.engine.GlobalExecutionContext;
-import org.hibernate.validator.engine.LocalExecutionContext;
+import org.hibernate.validator.engine.ValidationContext;
+import org.hibernate.validator.engine.ValueContext;
 import org.hibernate.validator.util.ReflectionHelper;
 
 /**
@@ -115,11 +115,11 @@
 		return constraintTree.getDescriptor().getElementType();
 	}
 
-	public <T, U, V> boolean validateConstraint(GlobalExecutionContext<T> executionContext, LocalExecutionContext<U, V> localExecutionContext) {
+	public <T, U, V> boolean validateConstraint(ValidationContext<T> executionContext, ValueContext<U, V> valueContext) {
 		List<ConstraintViolation<T>> constraintViolations = new ArrayList<ConstraintViolation<T>>();
-		localExecutionContext.setElementType( getElementType() );
+		valueContext.setElementType( getElementType() );
 		constraintTree.validateConstraints(
-				typeOfAnnotatedElement(), executionContext, localExecutionContext, constraintViolations
+				typeOfAnnotatedElement(), executionContext, valueContext, constraintViolations
 		);
 		if ( constraintViolations.size() > 0 ) {
 			executionContext.addConstraintFailures( constraintViolations );

Modified: validator/trunk/hibernate-validator-tck-runner/pom.xml
===================================================================
--- validator/trunk/hibernate-validator-tck-runner/pom.xml	2010-04-28 04:32:00 UTC (rev 19312)
+++ validator/trunk/hibernate-validator-tck-runner/pom.xml	2010-04-28 11:05:26 UTC (rev 19313)
@@ -1,5 +1,7 @@
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-    <modelVersion>4.0.0</modelVersion>    
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
     <parent>
         <artifactId>hibernate-validator-parent</artifactId>
         <groupId>org.hibernate</groupId>
@@ -17,7 +19,7 @@
         <dependency>
             <groupId>org.hibernate</groupId>
             <artifactId>hibernate-validator</artifactId>
-        </dependency>       
+        </dependency>
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-log4j12</artifactId>
@@ -50,13 +52,13 @@
             <groupId>com.sun.xml.bind</groupId>
             <artifactId>jaxb-impl</artifactId>
             <scope>provided</scope>
-        </dependency>         
+        </dependency>
     </dependencies>
 
     <properties>
         <jboss.home>/opt/java/jboss-5.1.0.GA</jboss.home>
         <validation.provider>org.hibernate.validator.HibernateValidator</validation.provider>
-        <remote.debug />
+        <remote.debug/>
     </properties>
 
     <build>



More information about the hibernate-commits mailing list