org.hibernate.validator.internal.metadata.core.MetaConstraint Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of bean-validator Show documentation
Show all versions of bean-validator Show documentation
JSR 380's RI, Hibernate Validator version ${hibernate-validator.version} and its dependencies repackaged as OSGi bundle
/*
* Hibernate Validator, declare and validate application constraints
*
* License: Apache License, Version 2.0
* See the license.txt file in the root directory or .
*/
package org.hibernate.validator.internal.metadata.core;
import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Set;
import javax.validation.valueextraction.ValueExtractor;
import org.hibernate.validator.internal.engine.ValidationContext;
import org.hibernate.validator.internal.engine.ValueContext;
import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree;
import org.hibernate.validator.internal.engine.valueextraction.ValueExtractorDescriptor;
import org.hibernate.validator.internal.engine.valueextraction.ValueExtractorHelper;
import org.hibernate.validator.internal.metadata.descriptor.ConstraintDescriptorImpl;
import org.hibernate.validator.internal.metadata.location.ConstraintLocation;
import org.hibernate.validator.internal.util.StringHelper;
import org.hibernate.validator.internal.util.stereotypes.Immutable;
/**
* Instances of this class abstract the constraint type (class, method or field constraint) and give access to
* meta data about the constraint. This allows a unified handling of constraints in the validator implementation.
*
* @author Hardy Ferentschik
* @author Gunnar Morling
* @author Guillaume Smet
*/
public class MetaConstraint {
/**
* The constraint tree created from the constraint annotation.
*/
private final ConstraintTree constraintTree;
/**
* The location at which this constraint is defined.
*/
private final ConstraintLocation location;
/**
* The path used to navigate from the outermost container to the innermost container and extract the value for
* validation.
*/
@Immutable
private final ValueExtractionPathNode valueExtractionPath;
private final int hashCode;
/**
* Indicates if the constraint is defined for one group only: used to optimize already validated constraints
* tracking.
*/
private final boolean isDefinedForOneGroupOnly;
/**
* @param constraintDescriptor The constraint descriptor for this constraint
* @param location meta data about constraint placement
* @param valueExtractorDescriptors the potential {@link ValueExtractor}s used to extract the value to validate
* @param validatedValueType the type of the validated element
*/
MetaConstraint(ConstraintDescriptorImpl constraintDescriptor, ConstraintLocation location, List valueExtractionPath,
Type validatedValueType) {
this.constraintTree = ConstraintTree.of( constraintDescriptor, validatedValueType );
this.location = location;
this.valueExtractionPath = getValueExtractionPath( valueExtractionPath );
this.hashCode = buildHashCode( constraintDescriptor, location );
this.isDefinedForOneGroupOnly = constraintDescriptor.getGroups().size() <= 1;
}
private static ValueExtractionPathNode getValueExtractionPath(List valueExtractionPath) {
switch ( valueExtractionPath.size() ) {
case 0: return null;
case 1: return new SingleValueExtractionPathNode( valueExtractionPath.iterator().next() );
default: return new LinkedValueExtractionPathNode( null, valueExtractionPath );
}
}
/**
* @return Returns the list of groups this constraint is part of. This might include the default group even when
* it is not explicitly specified, but part of the redefined default group list of the hosting bean.
*/
public final Set> getGroupList() {
return constraintTree.getDescriptor().getGroups();
}
public final boolean isDefinedForOneGroupOnly() {
return isDefinedForOneGroupOnly;
}
public final ConstraintDescriptorImpl getDescriptor() {
return constraintTree.getDescriptor();
}
public final ElementType getElementType() {
return constraintTree.getDescriptor().getElementType();
}
public boolean validateConstraint(ValidationContext validationContext, ValueContext valueContext) {
boolean success = true;
// constraint requiring value extraction to get the value to validate
if ( valueExtractionPath != null ) {
Object valueToValidate = valueContext.getCurrentValidatedValue();
if ( valueToValidate != null ) {
TypeParameterValueReceiver receiver = new TypeParameterValueReceiver( validationContext, valueContext, valueExtractionPath );
ValueExtractorHelper.extractValues( valueExtractionPath.getValueExtractorDescriptor(), valueToValidate, receiver );
success = receiver.isSuccess();
}
}
// regular constraint
else {
success = doValidateConstraint( validationContext, valueContext );
}
return success;
}
private boolean doValidateConstraint(ValidationContext executionContext, ValueContext valueContext) {
valueContext.setElementType( getElementType() );
boolean validationResult = constraintTree.validateConstraints( executionContext, valueContext );
return validationResult;
}
public ConstraintLocation getLocation() {
return location;
}
@Override
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( o == null || getClass() != o.getClass() ) {
return false;
}
MetaConstraint that = (MetaConstraint) o;
if ( !constraintTree.getDescriptor().equals( that.constraintTree.getDescriptor() ) ) {
return false;
}
if ( !location.equals( that.location ) ) {
return false;
}
return true;
}
private static int buildHashCode(ConstraintDescriptorImpl constraintDescriptor, ConstraintLocation location) {
final int prime = 31;
int result = 1;
result = prime * result + constraintDescriptor.hashCode();
result = prime * result + location.hashCode();
return result;
}
@Override
public int hashCode() {
return hashCode;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append( "MetaConstraint" );
sb.append( "{constraintType=" ).append( StringHelper.toShortString( constraintTree.getDescriptor().getAnnotation().annotationType() ) );
sb.append( ", location=" ).append( location );
sb.append( ", valueExtractionPath=" ).append( valueExtractionPath );
sb.append( "}" );
return sb.toString();
}
private final class TypeParameterValueReceiver implements ValueExtractor.ValueReceiver {
private final ValidationContext validationContext;
private final ValueContext valueContext;
private boolean success = true;
private ValueExtractionPathNode currentValueExtractionPathNode;
public TypeParameterValueReceiver(ValidationContext validationContext, ValueContext valueContext, ValueExtractionPathNode currentValueExtractionPathNode) {
this.validationContext = validationContext;
this.valueContext = valueContext;
this.currentValueExtractionPathNode = currentValueExtractionPathNode;
}
@Override
public void value(String nodeName, Object object) {
doValidate( object, nodeName );
}
@Override
public void iterableValue(String nodeName, Object value) {
valueContext.markCurrentPropertyAsIterable();
doValidate( value, nodeName );
}
@Override
public void indexedValue(String nodeName, int index, Object value) {
valueContext.markCurrentPropertyAsIterableAndSetIndex( index );
doValidate( value, nodeName );
}
@Override
public void keyedValue(String nodeName, Object key, Object value) {
valueContext.markCurrentPropertyAsIterableAndSetKey( key );
doValidate( value, nodeName );
}
private void doValidate(Object value, String nodeName) {
ValueContext.ValueState