Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * JBoss, Home of Professional Open Source
   * Copyright 2010, 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.List;
 import java.util.Map;
 import java.util.Set;
 
 
 import static org.hibernate.validator.constraints.CompositionType.ALL_FALSE;
 import static org.hibernate.validator.constraints.CompositionType.AND;
 import static org.hibernate.validator.constraints.CompositionType.OR;
 import static org.hibernate.validator.internal.util.CollectionHelper.newHashMap;
 import static org.hibernate.validator.internal.util.CollectionHelper.newHashSet;
 import static org.hibernate.validator.internal.util.ConcurrentReferenceHashMap.ReferenceType.SOFT;

Due to constraint composition a single constraint annotation can lead to a whole constraint tree being validated. This class encapsulates such a tree.

Author(s):
Hardy Ferentschik
Federico Mancini
Dag Hovland
Kevin Pollet <kevin.pollet@serli.com> (C) 2012 SERLI
 
 public class ConstraintTree<A extends Annotation> {
 	private static final Log log = LoggerFactory.make();

The default initial capacity for this cache.
 
 	static final int DEFAULT_INITIAL_CAPACITY = 16;
 
 	private final ConstraintTree<?> parent;
 	private final List<ConstraintTree<?>> children;

The constraint descriptor for the constraint represented by this constraint tree.
 
 	private final ConstraintDescriptorImpl<A> descriptor;

Cache for initialized ConstraintValidator instance per ConstraintValidatorFactory and validated type. This is necessary, because via aValidatorFactory.usingContext().constraintValidatorFactory(otherCVF) it is possible to create a Validator instance which is using a different constraint validator factory.

Also note, that ConstraintTree is part of the BeanMetaData which is cached on ValidatorFactory level. In most cases there is only one ConstraintValidator instance per ConstraintTree, unless aValidatorFactory.usingContext().constraintValidatorFactory(otherCVF) is used or the user classes are getting reloaded.

 
 
 	public ConstraintTree(ConstraintDescriptorImpl<A> descriptor) {
 		thisdescriptornull );
 	}
 
 	private ConstraintTree(ConstraintDescriptorImpl<A> descriptorConstraintTree<?> parent) {
 		this. = parent;
 		this. = descriptor;
 						,
 				);
 
 		final Set<ConstraintDescriptorImpl<?>> composingConstraints = newHashSet();
 		for ( ConstraintDescriptor<?> composingConstraint : descriptor.getComposingConstraints() ) {
 			composingConstraints.add( (ConstraintDescriptorImpl<?>) composingConstraint );
		}
		 = new ArrayList<ConstraintTree<?>>( composingConstraints.size() );
		for ( ConstraintDescriptorImpl<?> composingDescriptor : composingConstraints ) {
			ConstraintTree<?> treeNode = createConstraintTreecomposingDescriptor );
			.addtreeNode );
		}
	}
	private <U extends AnnotationConstraintTree<U> createConstraintTree(ConstraintDescriptorImpl<U> composingDescriptor) {
		return new ConstraintTree<U>( composingDescriptorthis );
	}
	public final List<ConstraintTree<?>> getChildren() {
		return ;
	}
		return ;
	}
	public final <T, U, V, E extends ConstraintViolation<T>> boolean validateConstraints(ValidationContext<T, E> executionContextValueContext<U, V> valueContext) {
		Set<E> constraintViolations = CollectionHelper.newHashSet();
		validateConstraintsexecutionContextvalueContextconstraintViolations );
		if ( !constraintViolations.isEmpty() ) {
			executionContext.addConstraintFailuresconstraintViolations );
			return false;
		}
		return true;
	}
	private <T, E extends ConstraintViolation<T>> boolean mainConstraintNeedsEvaluation(ValidationContext<T, E> executionContextSet<E> constraintViolations) {
		// there is no validator for the main constraints
			return false;
		}
		// report as single violation and there is already a violation
		if ( .isReportAsSingleViolation() && .getCompositionType() ==  && !constraintViolations.isEmpty() ) {
			return false;
		}
		// explicit fail fast mode
		if ( executionContext.isFailFastModeEnabled() && !constraintViolations.isEmpty() ) {
			return false;
		}
		return true;
	}
	private <T, U, V, E extends ConstraintViolation<T>> void validateConstraints(ValidationContext<T, E> executionContext,
																				 ValueContext<U, V> valueContext,
																				 Set<E> constraintViolations) {
				executionContextvalueContextconstraintViolations
		);
		Set<E> localViolationList = CollectionHelper.newHashSet();
		// After all children are validated the actual ConstraintValidator of the constraint itself is executed (provided
		// there is one)
		if ( mainConstraintNeedsEvaluationexecutionContextconstraintViolations ) ) {
			if ( .isTraceEnabled() ) {
						"Validating value %s against constraint defined by %s.",
				);
			}
			);
					valueContext.getPropertyPath(), 
			);
					executionContext,
					valueContext,
					constraintValidatorContext,
					validator,
					localViolationList
			);
			// We re-evaluate the boolean composition by taking into consideration also the violations
			// from the local constraintValidator
			if ( localViolationList.isEmpty() ) {
				compositionResult.setAtLeastOneTruetrue );
			}
			else {
				compositionResult.setAllTruefalse );
			}
		}
		if ( !passesCompositionTypeRequirementconstraintViolationscompositionResult ) ) {
					executionContextvalueContextconstraintViolationslocalViolationList
			);
		}
	}

Before the final constraint violations can be reported back we need to check whether we have a composing constraint whose result should be reported as single violation.

Parameters:
executionContext Meta data about top level validation
valueContext Meta data for currently validated value
constraintViolations Used to accumulate constraint violations
localViolationList List of constraint violations of top level constraint
	private <T, U, V, E extends ConstraintViolation<T>> void prepareFinalConstraintViolations(ValidationContext<T, E> executionContextValueContext<U, V> valueContextSet<E> constraintViolationsSet<E> localViolationList) {
			// We clear the current violations list anyway
			constraintViolations.clear();
			// But then we need to distinguish whether the local ConstraintValidator has reported
			// violations or not (or if there is no local ConstraintValidator at all).
			// If not we create a violation
			// using the error message in the annotation declaration at top level.
			if ( localViolationList.isEmpty() ) {
				final String message = (StringgetDescriptor().getAttributes().get"message" );
				MessageAndPath messageAndPath = new MessageAndPathmessagevalueContext.getPropertyPath() );
violation = executionContext.createConstraintViolation(
						valueContextmessageAndPath
				);
				constraintViolations.addviolation );
			}
		}
		// Now, if there were some violations reported by
		// the local ConstraintValidator, they need to be added to constraintViolations.
		// Whether we need to report them as a single constraint or just add them to the other violations
		// from the composing constraints, has been taken care of in the previous conditional block.
		// This takes also care of possible custom error messages created by the constraintValidator,
		// as checked in test CustomErrorMessage.java
		// If no violations have been reported from the local ConstraintValidator, or no such validator exists,
		// then we just add an empty list.
		constraintViolations.addAlllocalViolationList );
	}

Validates all composing constraints recursively.

Parameters:
executionContext Meta data about top level validation
valueContext Meta data for currently validated value
constraintViolations Used to accumulate constraint violations
Returns:
Returns an instance of CompositionResult relevant for boolean composition of constraints
	private <T, U, V, E extends ConstraintViolation<T>> CompositionResult validateComposingConstraints(ValidationContext<T, E> executionContext,
																									   ValueContext<U, V> valueContext,
																									   Set<E> constraintViolations) {
		CompositionResult compositionResult = new CompositionResulttruefalse );
		for ( ConstraintTree<?> tree : getChildren() ) {
			Set<E> tmpViolationList = CollectionHelper.newHashSet();
			tree.validateConstraintsexecutionContextvalueContexttmpViolationList );
			constraintViolations.addAlltmpViolationList );
			if ( tmpViolationList.isEmpty() ) {
				compositionResult.setAtLeastOneTruetrue );
				// no need to further validate constraints, because at least one validation passed
				if ( .getCompositionType() ==  ) {
					break;
				}
			}
			else {
				compositionResult.setAllTruefalse );
						&& ( executionContext.isFailFastModeEnabled() || .isReportAsSingleViolation() ) ) {
					break;
				}
			}
		}
		return compositionResult;
	}
	private boolean passesCompositionTypeRequirement(Set<?> constraintViolationsCompositionResult compositionResult) {
		boolean passedValidation = false;
		switch ( compositionType ) {
			case :
				passedValidation = compositionResult.isAtLeastOneTrue();
				break;
			case :
				passedValidation = compositionResult.isAllTrue();
				break;
			case :
				passedValidation = !compositionResult.isAtLeastOneTrue();
				break;
		}
		assert ( !passedValidation || !( compositionType ==  ) || constraintViolations.isEmpty() );
		if ( passedValidation ) {
			constraintViolations.clear();
		}
		return passedValidation;
	}
	private <T, U, V, E extends ConstraintViolation<T>> Set<E> validateSingleConstraint(ValidationContext<T, E> executionContext,
																						ValueContext<U, V> valueContext,
																						ConstraintValidatorContextImpl constraintValidatorContext,
																						ConstraintValidator<A, V> validator,
																						Set<E> constraintViolations) {
		boolean isValid;
		try {
			isValid = validator.isValidvalueContext.getCurrentValidatedValue(), constraintValidatorContext );
		}
		catch ( RuntimeException e ) {
		}
		if ( !isValid ) {
			//We do not add them these violations yet, since we don't know how they are
			//going to influence the final boolean evaluation
			constraintViolations.addAll(
							valueContextconstraintValidatorContext
					)
			);
		}
		return constraintViolations;
	}

Returns:
true if the current constraint should be reported as single violation, false otherwise. When using negation, we only report the single top-level violation, as it is hard, especially for ALL_FALSE to give meaningful reports
	private boolean reportAsSingleViolation() {
	}

Parameters:
validatedValueType The type of the value to be validated (the type of the member/class the constraint was placed on).
constraintFactory constraint factory used to instantiate the constraint validator.
Returns:
A initialized constraint validator matching the type of the value to be validated.
	@SuppressWarnings("unchecked")
	private <V> ConstraintValidator<A, V> getInitializedValidator(Type validatedValueTypeConstraintValidatorFactory constraintFactory) {
				constraintFactory,
				validatedValueType
		);
		ConstraintValidator<A, V> constraintValidator = (ConstraintValidator<A, V>) .getkey );
		if ( constraintValidator == null ) {
			Class<? extends ConstraintValidator<?, ?>> validatorClass = findMatchingValidatorClassvalidatedValueType );
			constraintValidator = createAndInitializeValidatorconstraintFactoryvalidatorClass );
			.putkeyconstraintValidator );
		}
		else {
			.tracef"Constraint validator %s found in cache."constraintValidator );
		}
		return constraintValidator;
	}
	@SuppressWarnings("unchecked")
	private <V> ConstraintValidator<A, V> createAndInitializeValidator(ConstraintValidatorFactory constraintFactoryClass<? extends ConstraintValidator<?, ?>> validatorClass) {
		ConstraintValidator<A, V> constraintValidator;
		constraintValidator = (ConstraintValidator<A, V>) constraintFactory.getInstance(
				validatorClass
		);
		if ( constraintValidator == null ) {
		}
		initializeConstraintconstraintValidator );
		return constraintValidator;
	}

Runs the validator resolution algorithm.

Parameters:
validatedValueType The type of the value to be validated (the type of the member/class the constraint was placed on).
Returns:
The class of a matching validator.
	private Class<? extends ConstraintValidator<?, ?>> findMatchingValidatorClass(Type validatedValueType) {
		Map<TypeClass<? extends ConstraintValidator<?, ?>>> availableValidatorTypes = TypeHelper.getValidatorsTypes(
		);
		Map<TypeTypesuitableTypeMap = newHashMap();
		if ( suitableTypeMap.containsKeyvalidatedValueType ) ) {
			return availableValidatorTypes.getsuitableTypeMap.getvalidatedValueType ) );
		}
		List<TypediscoveredSuitableTypes = findSuitableValidatorTypesvalidatedValueTypeavailableValidatorTypes );
		resolveAssignableTypesdiscoveredSuitableTypes );
		verifyResolveWasUniquevalidatedValueTypediscoveredSuitableTypes );
		Type suitableType = discoveredSuitableTypes.get( 0 );
		suitableTypeMap.putvalidatedValueTypesuitableType );
		return availableValidatorTypes.getsuitableType );
	}
	private void verifyResolveWasUnique(Type valueClassList<TypeassignableClasses) {
		if ( assignableClasses.size() == 0 ) {
			String className = valueClass.toString();
			if ( valueClass instanceof Class ) {
				Class<?> clazz = (Class<?>) valueClass;
				if ( clazz.isArray() ) {
					className = clazz.getComponentType().toString() + "[]";
				}
				else {
					className = clazz.getName();
				}
			}
		}
		else if ( assignableClasses.size() > 1 ) {
			StringBuilder builder = new StringBuilder();
			for ( Type clazz : assignableClasses ) {
				builder.appendclazz );
				builder.append", " );
			}
			builder.deletebuilder.length() - 2, builder.length() );
			throw .getMoreThanOneValidatorFoundForTypeExceptionvalueClassbuilder.toString() );
		}
	}
	private List<TypefindSuitableValidatorTypes(Type typeMap<TypeClass<? extends ConstraintValidator<?, ?>>> availableValidatorTypes) {
		List<TypedeterminedSuitableTypes = new ArrayList<Type>();
		for ( Type validatorType : availableValidatorTypes.keySet() ) {
			if ( TypeHelper.isAssignablevalidatorTypetype )
					&& !determinedSuitableTypes.containsvalidatorType ) ) {
				determinedSuitableTypes.addvalidatorType );
			}
		}
		return determinedSuitableTypes;
	}

Tries to reduce all assignable classes down to a single class.

Parameters:
assignableTypes The set of all classes which are assignable to the class of the value to be validated and which are handled by at least one of the validators for the specified constraint.
	private void resolveAssignableTypes(List<TypeassignableTypes) {
		if ( assignableTypes.size() == 0 || assignableTypes.size() == 1 ) {
			return;
		}
		List<TypetypesToRemove = new ArrayList<Type>();
		do {
			typesToRemove.clear();
			Type type = assignableTypes.get( 0 );
			for ( int i = 1; i < assignableTypes.size(); i++ ) {
				if ( TypeHelper.isAssignabletypeassignableTypes.geti ) ) ) {
					typesToRemove.addtype );
				}
				else if ( TypeHelper.isAssignableassignableTypes.geti ), type ) ) {
					typesToRemove.addassignableTypes.geti ) );
				}
			}
			assignableTypes.removeAlltypesToRemove );
while ( typesToRemove.size() > 0 );
	}
	private <V> void initializeConstraint(ConstraintDescriptor<A> descriptorConstraintValidator<A, V> constraintValidator) {
		try {
			constraintValidator.initializedescriptor.getAnnotation() );
		}
		catch ( RuntimeException e ) {
		}
	}
	public String toString() {
		final StringBuilder sb = new StringBuilder();
		sb.append"ConstraintTree" );
		sb.append"{ descriptor=" ).append );
		sb.append", isRoot=" ).append == null );
		sb.append'}' );
		return sb.toString();
	}
	private static final class ConstraintValidatorCacheKey {
		private ConstraintValidatorCacheKey(ConstraintValidatorFactory constraintValidatorFactoryType validatorType) {
			this. = constraintValidatorFactory;
			this. = validatorType;
		}
		public boolean equals(Object o) {
			if ( this == o ) {
				return true;
			}
			if ( o == null || getClass() != o.getClass() ) {
				return false;
			}
			if (  != null ? !.equalsthat.constraintValidatorFactory ) : that.constraintValidatorFactory != null ) {
				return false;
			}
			if (  != null ? !.equalsthat.validatedType ) : that.validatedType != null ) {
				return false;
			}
			return true;
		}
		public int hashCode() {
			int result =  != null ? .hashCode() : 0;
			result = 31 * result + (  != null ? .hashCode() : 0 );
			return result;
		}
	}
	private static final class CompositionResult {
		private boolean allTrue;
		private boolean atLeastOneTrue;
		CompositionResult(boolean allTrueboolean atLeastOneTrue) {
			this. = allTrue;
			this. = atLeastOneTrue;
		}
		public boolean isAllTrue() {
			return ;
		}
		public boolean isAtLeastOneTrue() {
		}
		public void setAllTrue(boolean allTrue) {
			this. = allTrue;
		}
		public void setAtLeastOneTrue(boolean atLeastOneTrue) {
			this. = atLeastOneTrue;
		}
	}
New to GrepCode? Check out our FAQ X