Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
gunnarmorling committed Sep 18, 2017
1 parent bf7b5c0 commit da77077
Show file tree
Hide file tree
Showing 25 changed files with 507 additions and 479 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorContextImpl;
import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorManager;
import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintViolationCreationContext;
import org.hibernate.validator.internal.engine.path.PathBuilder;
import org.hibernate.validator.internal.engine.path.PathImpl;
import org.hibernate.validator.internal.metadata.BeanMetaDataManager;
import org.hibernate.validator.internal.metadata.aggregated.BeanMetaData;
Expand Down Expand Up @@ -285,7 +286,7 @@ public ConstraintViolation<T> createConstraintViolation(ValueContext<?, ?> local
constraintViolationCreationContext.getExpressionVariables()
);
// at this point we make a copy of the path to avoid side effects
Path path = PathImpl.createCopy( constraintViolationCreationContext.getPath() );
Path path = constraintViolationCreationContext.getPath().build();
Object dynamicPayload = constraintViolationCreationContext.getDynamicPayload();
if ( executableParameters != null ) {
return ConstraintViolationImpl.forParameterValidation(
Expand Down Expand Up @@ -426,10 +427,10 @@ private boolean isAlreadyValidatedForCurrentGroup(Object value, Class<?> group)
return processedUnits.contains( new BeanGroupProcessedUnit( value, group ) );
}

private void markCurrentBeanAsProcessedForCurrentPath(Object bean, PathImpl path) {
private void markCurrentBeanAsProcessedForCurrentPath(Object bean, PathBuilder path) {
// HV-1031 The path object is mutated as we traverse the object tree, hence copy it before saving it
processedPathsPerBean.computeIfAbsent( bean, b -> new HashSet<>() )
.add( PathImpl.createCopy( path ) );
.add( path.build() );
}

private void markCurrentBeanAsProcessedForCurrentGroup(Object bean, Class<?> group) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,15 @@
import javax.validation.valueextraction.ValueExtractor;

import org.hibernate.validator.internal.engine.ValidationContext.ValidationContextBuilder;
import org.hibernate.validator.internal.engine.ValueContext.ValueState;
import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorManager;
import org.hibernate.validator.internal.engine.groups.Group;
import org.hibernate.validator.internal.engine.groups.GroupWithInheritance;
import org.hibernate.validator.internal.engine.groups.Sequence;
import org.hibernate.validator.internal.engine.groups.ValidationOrder;
import org.hibernate.validator.internal.engine.groups.ValidationOrderGenerator;
import org.hibernate.validator.internal.engine.path.NodeImpl;
import org.hibernate.validator.internal.engine.path.PathImpl;
import org.hibernate.validator.internal.engine.path.PathBuilder;
import org.hibernate.validator.internal.engine.resolver.CachingTraversableResolverForSingleValidation;
import org.hibernate.validator.internal.engine.valueextraction.ValueExtractorDescriptor;
import org.hibernate.validator.internal.engine.valueextraction.ValueExtractorHelper;
Expand Down Expand Up @@ -177,7 +178,7 @@ public final <T> Set<ConstraintViolation<T>> validate(T object, Class<?>... grou
parameterNameProvider,
object,
validationContext.getRootBeanMetaData(),
PathImpl.createRootPath()
PathBuilder.createRootPath()
);

return validateInContext( validationContext, valueContext, validationOrder );
Expand All @@ -195,7 +196,7 @@ public final <T> Set<ConstraintViolation<T>> validateProperty(T object, String p
return Collections.emptySet();
}

PathImpl propertyPath = PathImpl.createPathFromString( propertyName );
PathBuilder propertyPath = PathBuilder.createPathFromString( propertyName );
ValueContext<?, Object> valueContext = getValueContextForPropertyValidation( validationContext, propertyPath );

if ( valueContext.getCurrentBean() == null ) {
Expand Down Expand Up @@ -224,7 +225,7 @@ public final <T> Set<ConstraintViolation<T>> validateValue(Class<T> beanType, St
return validateValueInContext(
validationContext,
value,
PathImpl.createPathFromString( propertyName ),
PathBuilder.createPathFromString( propertyName ),
validationOrder
);
}
Expand Down Expand Up @@ -551,11 +552,11 @@ private boolean validateMetaConstraint(ValidationContext<?> validationContext, V

success = metaConstraint.validateConstraint( validationContext, valueContext );

validationContext.markConstraintProcessed( valueContext.getCurrentBean(), valueContext.getPropertyPath(), metaConstraint );
validationContext.markConstraintProcessed( valueContext.getCurrentBean(), valueContext.getPropertyPath().build(), metaConstraint );
}

// reset the value context to the state before this call
valueContext.resetValueState( originalValueState );
valueContext.resetValueState( originalValueState, true );

return success;
}
Expand Down Expand Up @@ -600,13 +601,13 @@ private void validateCascadedConstraints(ValidationContext<?> validationContext,
}

// reset the value context
valueContext.resetValueState( originalValueState );
valueContext.resetValueState( originalValueState, true );
}
}

private void validateCascadedAnnotatedObjectForCurrentGroup(Object value, ValidationContext<?> validationContext, ValueContext<?, Object> valueContext,
CascadingMetaData cascadingMetaData) {
if ( validationContext.isBeanAlreadyValidated( value, valueContext.getCurrentGroup(), valueContext.getPropertyPath() ) ||
if ( validationContext.isBeanAlreadyValidated( value, valueContext.getCurrentGroup(), valueContext.getPropertyPath().build() ) ||
shouldFailFast( validationContext ) ) {
return;
}
Expand Down Expand Up @@ -682,7 +683,7 @@ public void keyedValue(String nodeName, Object key, Object value) {

private void doValidate(Object value, String nodeName) {
if ( value == null ||
validationContext.isBeanAlreadyValidated( value, valueContext.getCurrentGroup(), valueContext.getPropertyPath() ) ||
validationContext.isBeanAlreadyValidated( value, valueContext.getCurrentGroup(), valueContext.getPropertyPath().build() ) ||
shouldFailFast( validationContext ) ) {
return;
}
Expand Down Expand Up @@ -713,11 +714,15 @@ private void doValidate(Object value, String nodeName) {
cascadedValueContext.setTypeParameter( cascadingMetaData.getDeclaredContainerClass(), cascadingMetaData.getDeclaredTypeParameter() );
}

ValueState<Object> valueState = cascadedTypeArgumentValueContext.getCurrentValueState();

if ( nodeName != null ) {
cascadedTypeArgumentValueContext.appendTypeParameterNode( nodeName );
}

validateCascadedContainerElementsInContext( value, validationContext, cascadedTypeArgumentValueContext, cascadingMetaData, validationOrder );

cascadedTypeArgumentValueContext.resetValueState( valueState, nodeName != null );
}
}
}
Expand Down Expand Up @@ -780,7 +785,7 @@ private ValueContext<?, Object> buildNewLocalExecutionContext(ValueContext<?, ?>
return newValueContext;
}

private <T> Set<ConstraintViolation<T>> validateValueInContext(ValidationContext<T> validationContext, Object value, PathImpl propertyPath,
private <T> Set<ConstraintViolation<T>> validateValueInContext(ValidationContext<T> validationContext, Object value, PathBuilder propertyPath,
ValidationOrder validationOrder) {
ValueContext<?, Object> valueContext = getValueContextForValueValidation( validationContext, propertyPath );
valueContext.setCurrentValidatedValue( value );
Expand Down Expand Up @@ -868,7 +873,7 @@ private <T> void validateParametersInContext(ValidationContext<T> validationCont
parameterNameProvider,
parameterValues,
executableMetaData.getValidatableParametersMetaData(),
PathImpl.createPathForExecutable( executableMetaData )
PathBuilder.createPathForExecutable( executableMetaData )
);

groupIterator = validationOrder.getGroupIterator();
Expand Down Expand Up @@ -1002,7 +1007,7 @@ private <T> ValueContext<T, Object> getExecutableValueContext(T object, Executab
parameterNameProvider,
object,
validatable,
PathImpl.createPathForExecutable( executableMetaData )
PathBuilder.createPathForExecutable( executableMetaData )
);
}
else {
Expand All @@ -1011,7 +1016,7 @@ private <T> ValueContext<T, Object> getExecutableValueContext(T object, Executab
parameterNameProvider,
(Class<T>) null, //the type is not required in this case (only for cascaded validation)
validatable,
PathImpl.createPathForExecutable( executableMetaData )
PathBuilder.createPathForExecutable( executableMetaData )
);
}

Expand Down Expand Up @@ -1054,7 +1059,7 @@ private <V, T> void validateReturnValueInContext(ValidationContext<T> validation
parameterNameProvider,
value,
executableMetaData.getReturnValueMetaData(),
PathImpl.createPathForExecutable( executableMetaData )
PathBuilder.createPathForExecutable( executableMetaData )
);

groupIterator = validationOrder.getGroupIterator();
Expand Down Expand Up @@ -1159,7 +1164,7 @@ private <T> void validateReturnValueForSingleGroup(ValidationContext<T> validati
* @return Returns an instance of {@code ValueContext} which describes the local validation context associated to
* the given property path.
*/
private <V> ValueContext<?, V> getValueContextForPropertyValidation(ValidationContext<?> validationContext, PathImpl propertyPath) {
private <V> ValueContext<?, V> getValueContextForPropertyValidation(ValidationContext<?> validationContext, PathBuilder propertyPath) {
Class<?> clazz = validationContext.getRootBeanClass();
BeanMetaData<?> beanMetaData = validationContext.getRootBeanMetaData();
Object value = validationContext.getRootBean();
Expand Down Expand Up @@ -1237,7 +1242,7 @@ else if ( propertyPathNode.getKey() != null ) {
* the given property path.
*/
private <V> ValueContext<?, V> getValueContextForValueValidation(ValidationContext<?> validationContext,
PathImpl propertyPath) {
PathBuilder propertyPath) {
Class<?> clazz = validationContext.getRootBeanClass();
BeanMetaData<?> beanMetaData = null;
PropertyMetaData propertyMetaData = null;
Expand Down Expand Up @@ -1298,7 +1303,7 @@ private boolean isValidationRequired(ValidationContext<?> validationContext,
}
if ( validationContext.hasMetaConstraintBeenProcessed(
valueContext.getCurrentBean(),
valueContext.getPropertyPath(),
valueContext.getPropertyPath().build(),
metaConstraint
) ) {
return false;
Expand All @@ -1315,7 +1320,7 @@ private boolean isValidationRequired(ValidationContext<?> validationContext,
);
}

private boolean isReachable(ValidationContext<?> validationContext, Object traversableObject, PathImpl path, ElementType type) {
private boolean isReachable(ValidationContext<?> validationContext, Object traversableObject, PathBuilder path, ElementType type) {
if ( needToCallTraversableResolver( path, type ) ) {
return true;
}
Expand All @@ -1335,7 +1340,7 @@ private boolean isReachable(ValidationContext<?> validationContext, Object trave
}
}

private boolean needToCallTraversableResolver(PathImpl path, ElementType type) {
private boolean needToCallTraversableResolver(PathBuilder path, ElementType type) {
// as the TraversableResolver interface is designed right now it does not make sense to call it when
// there is no traversable object hosting the property to be accessed. For this reason we don't call the resolver
// for class level constraints (ElementType.TYPE) or top level method parameters or return values.
Expand All @@ -1346,7 +1351,7 @@ private boolean needToCallTraversableResolver(PathImpl path, ElementType type) {
|| isReturnValueValidation( path );
}

private boolean isCascadeRequired(ValidationContext<?> validationContext, Object traversableObject, PathImpl path, ElementType type) {
private boolean isCascadeRequired(ValidationContext<?> validationContext, Object traversableObject, PathBuilder path, ElementType type) {
if ( needToCallTraversableResolver( path, type ) ) {
return true;
}
Expand Down Expand Up @@ -1375,15 +1380,15 @@ private boolean isClassLevelConstraint(ElementType type) {
return ElementType.TYPE.equals( type );
}

private boolean isCrossParameterValidation(PathImpl path) {
private boolean isCrossParameterValidation(PathBuilder path) {
return path.getLeafNode().getKind() == ElementKind.CROSS_PARAMETER;
}

private boolean isParameterValidation(PathImpl path) {
private boolean isParameterValidation(PathBuilder path) {
return path.getLeafNode().getKind() == ElementKind.PARAMETER;
}

private boolean isReturnValueValidation(PathImpl path) {
private boolean isReturnValueValidation(PathBuilder path) {
return path.getLeafNode().getKind() == ElementKind.RETURN_VALUE;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

import javax.validation.groups.Default;

import org.hibernate.validator.internal.engine.path.PathImpl;
import org.hibernate.validator.internal.engine.path.PathBuilder;
import org.hibernate.validator.internal.engine.valueextraction.AnnotatedObject;
import org.hibernate.validator.internal.engine.valueextraction.ArrayElement;
import org.hibernate.validator.internal.metadata.BeanMetaDataManager;
Expand Down Expand Up @@ -52,7 +52,7 @@ public class ValueContext<T, V> {
/**
* The current property path we are validating.
*/
private PathImpl propertyPath;
private final PathBuilder propertyPath;

/**
* The current group we are validating.
Expand All @@ -72,32 +72,32 @@ public class ValueContext<T, V> {
private ElementType elementType;

public static <T, V> ValueContext<T, V> getLocalExecutionContext(BeanMetaDataManager beanMetaDataManager,
ExecutableParameterNameProvider parameterNameProvider, T value, Validatable validatable, PathImpl propertyPath) {
ExecutableParameterNameProvider parameterNameProvider, T value, Validatable validatable, PathBuilder propertyPath) {
@SuppressWarnings("unchecked")
Class<T> rootBeanType = (Class<T>) value.getClass();
return new ValueContext<>( parameterNameProvider, value, rootBeanType, beanMetaDataManager.getBeanMetaData( rootBeanType ), validatable, propertyPath );
}

@SuppressWarnings("unchecked")
public static <T, V> ValueContext<T, V> getLocalExecutionContext(ExecutableParameterNameProvider parameterNameProvider, T value,
BeanMetaData<?> currentBeanMetaData, PathImpl propertyPath) {
BeanMetaData<?> currentBeanMetaData, PathBuilder propertyPath) {
Class<T> rootBeanType = (Class<T>) value.getClass();
return new ValueContext<>( parameterNameProvider, value, rootBeanType, (BeanMetaData<T>) currentBeanMetaData, currentBeanMetaData, propertyPath );
}

public static <T, V> ValueContext<T, V> getLocalExecutionContext(BeanMetaDataManager beanMetaDataManager,
ExecutableParameterNameProvider parameterNameProvider, Class<T> rootBeanType, Validatable validatable, PathImpl propertyPath) {
ExecutableParameterNameProvider parameterNameProvider, Class<T> rootBeanType, Validatable validatable, PathBuilder propertyPath) {
BeanMetaData<T> rootBeanMetaData = rootBeanType != null ? beanMetaDataManager.getBeanMetaData( rootBeanType ) : null;
return new ValueContext<>( parameterNameProvider, null, rootBeanType, rootBeanMetaData, validatable, propertyPath );
}

@SuppressWarnings("unchecked")
public static <T, V> ValueContext<T, V> getLocalExecutionContext(ExecutableParameterNameProvider parameterNameProvider, Class<T> currentBeanType,
BeanMetaData<?> currentBeanMetaData, PathImpl propertyPath) {
BeanMetaData<?> currentBeanMetaData, PathBuilder propertyPath) {
return new ValueContext<>( parameterNameProvider, null, currentBeanType, (BeanMetaData<T>) currentBeanMetaData, currentBeanMetaData, propertyPath );
}

private ValueContext(ExecutableParameterNameProvider parameterNameProvider, T currentBean, Class<T> currentBeanType, BeanMetaData<T> currentBeanMetaData, Validatable validatable, PathImpl propertyPath) {
private ValueContext(ExecutableParameterNameProvider parameterNameProvider, T currentBean, Class<T> currentBeanType, BeanMetaData<T> currentBeanMetaData, Validatable validatable, PathBuilder propertyPath) {
this.parameterNameProvider = parameterNameProvider;
this.currentBean = currentBean;
this.currentBeanType = currentBeanType;
Expand All @@ -106,7 +106,7 @@ private ValueContext(ExecutableParameterNameProvider parameterNameProvider, T cu
this.propertyPath = propertyPath;
}

public final PathImpl getPropertyPath() {
public final PathBuilder getPropertyPath() {
return propertyPath;
}

Expand Down Expand Up @@ -138,21 +138,15 @@ public final Object getCurrentValidatedValue() {
}

public final void appendNode(Cascadable node) {
PathImpl newPath = PathImpl.createCopy( propertyPath );
node.appendTo( newPath );
propertyPath = newPath;
node.appendTo( propertyPath );
}

public final void appendNode(ConstraintLocation location) {
PathImpl newPath = PathImpl.createCopy( propertyPath );
location.appendTo( parameterNameProvider, newPath );
propertyPath = newPath;
location.appendTo( parameterNameProvider, propertyPath );
}

public final void appendTypeParameterNode(String nodeName) {
PathImpl newPath = PathImpl.createCopy( propertyPath );
newPath.addContainerElementNode( nodeName );
propertyPath = newPath;
propertyPath.addContainerElementNode( nodeName );
}

public final void markCurrentPropertyAsIterable() {
Expand Down Expand Up @@ -209,11 +203,13 @@ public final void setElementType(ElementType elementType) {
}

public final ValueState<V> getCurrentValueState() {
return new ValueState<V>( propertyPath, currentValue );
return new ValueState<>( currentValue );
}

public final void resetValueState(ValueState<V> valueState) {
this.propertyPath = valueState.propertyPath;
public final void resetValueState(ValueState<V> valueState, boolean resetPath) {
if ( resetPath ) {
this.propertyPath.removeLeafNode();
}
this.currentValue = valueState.currentValue;
}

Expand All @@ -238,12 +234,9 @@ public Object getValue(Object parent, ConstraintLocation location) {

public static class ValueState<V> {

private final PathImpl propertyPath;

private final V currentValue;

private ValueState(PathImpl propertyPath, V currentValue) {
this.propertyPath = propertyPath;
private ValueState(V currentValue) {
this.currentValue = currentValue;
}
}
Expand Down
Loading

0 comments on commit da77077

Please sign in to comment.