Skip to content

Commit

Permalink
HV-1148 Pushing logic for appending path nodes to specific sub-types …
Browse files Browse the repository at this point in the history
…of ConstraintLocation
  • Loading branch information
gunnarmorling committed Nov 8, 2016
1 parent 0e8a053 commit 91e782b
Show file tree
Hide file tree
Showing 17 changed files with 772 additions and 185 deletions.
Expand Up @@ -65,6 +65,12 @@ public static <A extends Annotation> ConfiguredConstraint<A> forExecutable(Const
);
}

public static <A extends Annotation> ConfiguredConstraint<A> forCrossParameter(ConstraintDef<?, A> constraint, Executable executable) {
return new ConfiguredConstraint<>(
constraint, ConstraintLocation.forCrossParameter( executable ), ExecutableHelper.getElementType( executable )
);
}

public ConstraintDef<?, A> getConstraint() {
return constraint;
}
Expand Down
Expand Up @@ -32,7 +32,7 @@ final class CrossParameterConstraintMappingContextImpl

@Override
public CrossParameterConstraintMappingContext constraint(ConstraintDef<?, ?> definition) {
super.addConstraint( ConfiguredConstraint.forExecutable( definition, executableContext.getExecutable() ) );
super.addConstraint( ConfiguredConstraint.forCrossParameter( definition, executableContext.getExecutable() ) );
return this;
}

Expand Down
Expand Up @@ -196,6 +196,7 @@ public final <T> Set<ConstraintViolation<T>> validate(T object, Class<?>... grou
ValidationContext<T> validationContext = getValidationContext().forValidate( object );

ValueContext<?, Object> valueContext = ValueContext.getLocalExecutionContext(
parameterNameProvider,
object,
beanMetaDataManager.getBeanMetaData( object.getClass() ),
PathImpl.createRootPath()
Expand Down Expand Up @@ -554,14 +555,14 @@ private boolean validateConstraint(ValidationContext<?> validationContext,

boolean validationSuccessful;

if ( !propertyPathComplete ) {
valueContext.appendNode( metaConstraint.getLocation() );
}

if ( metaConstraint.getElementType() != ElementType.TYPE ) {
PropertyMetaData propertyMetaData = beanMetaDataManager.getBeanMetaData( valueContext.getCurrentBeanType() )
.getMetaDataFor( metaConstraint.getLocation().getPropertyName() );

if ( !propertyPathComplete ) {
valueContext.appendNode( propertyMetaData );
}

if ( ElementType.TYPE_USE.equals( metaConstraint.getElementType() ) ) {
// TYPE_USE constraints always require UNWRAP
valueContext.setUnwrapMode( UnwrapMode.UNWRAP );
Expand All @@ -571,9 +572,6 @@ private boolean validateConstraint(ValidationContext<?> validationContext,
valueContext.setUnwrapMode( propertyMetaData.unwrapMode() );
}
}
else {
valueContext.appendBeanNode();
}

validationSuccessful = validateMetaConstraint( validationContext, valueContext, metaConstraint );

Expand Down Expand Up @@ -763,13 +761,15 @@ private ValueContext<?, Object> buildNewLocalExecutionContext(ValueContext<?, Ob
ValueContext<?, Object> newValueContext;
if ( value != null ) {
newValueContext = ValueContext.getLocalExecutionContext(
parameterNameProvider,
value,
beanMetaDataManager.getBeanMetaData( value.getClass() ),
valueContext.getPropertyPath()
);
}
else {
newValueContext = ValueContext.getLocalExecutionContext(
parameterNameProvider,
valueContext.getCurrentBeanType(),
beanMetaDataManager.getBeanMetaData( valueContext.getCurrentBeanType() ),
valueContext.getPropertyPath()
Expand All @@ -782,10 +782,12 @@ private void validateTypeArgumentConstraints(ValidationContext<?> context,
ValueContext<?, Object> valueContext,
Object value,
Set<MetaConstraint<?>> typeArgumentsConstraints) {
PathImpl previousPath = valueContext.getPropertyPath();
valueContext.setCurrentValidatedValue( value );
valueContext.appendCollectionElementNode();
for ( MetaConstraint<?> metaConstraint : typeArgumentsConstraints ) {
valueContext.appendNode( metaConstraint.getLocation() );
metaConstraint.validateConstraint( context, valueContext );
valueContext.setPropertyPath( previousPath );
if ( shouldFailFast( context ) ) {
return;
}
Expand Down Expand Up @@ -1101,6 +1103,7 @@ private <T> void validateParametersInContext(ValidationContext<T> validationCont
}

ValueContext<Object[], Object> cascadingValueContext = ValueContext.getLocalExecutionContext(
parameterNameProvider,
parameterValues,
executableMetaData.getValidatableParametersMetaData(),
PathImpl.createPathForExecutable( executableMetaData )
Expand Down Expand Up @@ -1192,21 +1195,26 @@ private <T> void validateParametersForGroup(ValidationContext<T> validationConte
}

private <T> void validateParametersForSingleGroup(ValidationContext<T> validationContext, Object[] parameterValues, ExecutableMetaData executableMetaData, Class<?> currentValidatedGroup) {
ValueContext<T, Object> valueContext = getExecutableValueContext(
validationContext.getRootBean(), executableMetaData, currentValidatedGroup
);
valueContext.appendCrossParameterNode();
valueContext.setCurrentValidatedValue( parameterValues );
if ( !executableMetaData.getCrossParameterConstraints().isEmpty() ) {
ValueContext<T, Object> valueContext = getExecutableValueContext(
validationContext.getRootBean(), executableMetaData, currentValidatedGroup
);

// 1. validate cross-parameter constraints
validateConstraintsForGroup(
validationContext, valueContext, executableMetaData.getCrossParameterConstraints()
);
if ( shouldFailFast( validationContext ) ) {
return;
MetaConstraint<?> firstConstraint = executableMetaData.getCrossParameterConstraints().iterator().next();
valueContext.appendNode( firstConstraint.getLocation() );

valueContext.setCurrentValidatedValue( parameterValues );

// 1. validate cross-parameter constraints
validateConstraintsForGroup(
validationContext, valueContext, executableMetaData.getCrossParameterConstraints()
);
if ( shouldFailFast( validationContext ) ) {
return;
}
}

valueContext = getExecutableValueContext(
ValueContext<T, Object> valueContext = getExecutableValueContext(
validationContext.getRootBean(), executableMetaData, currentValidatedGroup
);
valueContext.setCurrentValidatedValue( parameterValues );
Expand Down Expand Up @@ -1265,13 +1273,15 @@ private <T> ValueContext<T, Object> getExecutableValueContext(T object, Executab

if ( object != null ) {
valueContext = ValueContext.getLocalExecutionContext(
parameterNameProvider,
object,
null,
PathImpl.createPathForExecutable( executableMetaData )
);
}
else {
valueContext = ValueContext.getLocalExecutionContext(
parameterNameProvider,
(Class<T>) null, //the type is not required in this case (only for cascaded validation)
null,
PathImpl.createPathForExecutable( executableMetaData )
Expand Down Expand Up @@ -1309,6 +1319,7 @@ private <V, T> void validateReturnValueInContext(ValidationContext<T> context, T

if ( value != null ) {
cascadingValueContext = ValueContext.getLocalExecutionContext(
parameterNameProvider,
value,
executableMetaData.getReturnValueMetaData(),
PathImpl.createPathForExecutable( executableMetaData )
Expand Down Expand Up @@ -1509,7 +1520,7 @@ else if ( propertyPathNode.getKey() != null ) {
metaConstraints.addAll( propertyMetaData.getConstraints() );
typeArgumentConstraints.addAll( propertyMetaData.getTypeArgumentsConstraints() );

return ValueContext.getLocalExecutionContext( value, null, propertyPath );
return ValueContext.getLocalExecutionContext( parameterNameProvider, value, null, propertyPath );
}

/**
Expand Down Expand Up @@ -1563,7 +1574,7 @@ private <V> ValueContext<?, V> collectMetaConstraintsForPathWithoutValue(Validat
metaConstraints.addAll( propertyMetaData.getConstraints() );
typeArgumentConstraints.addAll( propertyMetaData.getTypeArgumentsConstraints() );

return ValueContext.getLocalExecutionContext( clazz, null, propertyPath );
return ValueContext.getLocalExecutionContext( parameterNameProvider, clazz, null, propertyPath );
}

/**
Expand Down
Expand Up @@ -15,6 +15,8 @@
import org.hibernate.validator.internal.engine.valuehandling.UnwrapMode;
import org.hibernate.validator.internal.metadata.facets.Cascadable;
import org.hibernate.validator.internal.metadata.facets.Validatable;
import org.hibernate.validator.internal.metadata.location.ConstraintLocation;
import org.hibernate.validator.internal.util.ExecutableParameterNameProvider;
import org.hibernate.validator.spi.valuehandling.ValidatedValueUnwrapper;

/**
Expand All @@ -25,6 +27,9 @@
* @author Gunnar Morling
*/
public class ValueContext<T, V> {

private final ExecutableParameterNameProvider parameterNameProvider;

/**
* The current bean which gets validated. This is the bean hosting the constraints which get validated.
*/
Expand Down Expand Up @@ -72,17 +77,18 @@ public class ValueContext<T, V> {
*/
private UnwrapMode unwrapMode = UnwrapMode.AUTOMATIC;

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

public static <T, V> ValueContext<T, V> getLocalExecutionContext(Class<T> type, Validatable validatable, PathImpl propertyPath) {
return new ValueContext<>( null, type, validatable, propertyPath );
public static <T, V> ValueContext<T, V> getLocalExecutionContext(ExecutableParameterNameProvider parameterNameProvider, Class<T> type, Validatable validatable, PathImpl propertyPath) {
return new ValueContext<>( parameterNameProvider, null, type, validatable, propertyPath );
}

private ValueContext(T currentBean, Class<T> currentBeanType, Validatable validatable, PathImpl propertyPath) {
private ValueContext(ExecutableParameterNameProvider parameterNameProvider, T currentBean, Class<T> currentBeanType, Validatable validatable, PathImpl propertyPath) {
this.parameterNameProvider = parameterNameProvider;
this.currentBean = currentBean;
this.currentBeanType = currentBeanType;
this.currentValidatable = validatable;
Expand Down Expand Up @@ -129,19 +135,10 @@ public final void appendNode(Cascadable node) {
propertyPath = newPath;
}

public final void appendCollectionElementNode() {
propertyPath = PathImpl.createCopy( propertyPath );
propertyPath.addCollectionElementNode();
}

public final void appendBeanNode() {
propertyPath = PathImpl.createCopy( propertyPath );
propertyPath.addBeanNode();
}

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

public final void markCurrentPropertyAsIterable() {
Expand Down
Expand Up @@ -38,8 +38,6 @@
import org.hibernate.validator.internal.metadata.raw.ConstrainedParameter;
import org.hibernate.validator.internal.util.ExecutableHelper;
import org.hibernate.validator.internal.util.ReflectionHelper;
import org.hibernate.validator.internal.util.logging.Log;
import org.hibernate.validator.internal.util.logging.LoggerFactory;

/**
* An aggregated view of the constraint related meta data for a given method or
Expand All @@ -60,8 +58,6 @@
*/
public class ExecutableMetaData extends AbstractConstraintMetaData {

private static final Log log = LoggerFactory.make();

private final Class<?>[] parameterTypes;
private final List<ParameterMetaData> parameterMetaDataList;
private final Set<MetaConstraint<?>> crossParameterConstraints;
Expand Down
Expand Up @@ -6,6 +6,9 @@
*/
package org.hibernate.validator.internal.metadata.aggregated;

import static org.hibernate.validator.internal.util.CollectionHelper.newHashMap;
import static org.hibernate.validator.internal.util.CollectionHelper.newHashSet;

import java.lang.annotation.Annotation;
import java.util.Map;
import java.util.Map.Entry;
Expand All @@ -17,13 +20,11 @@
import org.hibernate.validator.internal.metadata.core.MetaConstraint;
import org.hibernate.validator.internal.metadata.descriptor.ConstraintDescriptorImpl;
import org.hibernate.validator.internal.metadata.raw.ConstrainedElement;
import org.hibernate.validator.internal.metadata.raw.ConstrainedElement.ConstrainedElementKind;
import org.hibernate.validator.internal.util.CollectionHelper;
import org.hibernate.validator.internal.util.logging.Log;
import org.hibernate.validator.internal.util.logging.LoggerFactory;

import static org.hibernate.validator.internal.util.CollectionHelper.newHashMap;
import static org.hibernate.validator.internal.util.CollectionHelper.newHashSet;

/**
* Builds {@link ConstraintMetaData} instances for the
* {@link ConstrainedElement} objects representing one method or property in a
Expand Down Expand Up @@ -68,7 +69,7 @@ protected MetaDataBuilder(Class<?> beanClass, ConstraintHelper constraintHelper)
* @param constrainedElement The element to add.
*/
public void add(ConstrainedElement constrainedElement) {
constraints.addAll( constrainedElement.getConstraints() );
constraints.addAll( adaptConstraints( constrainedElement.getKind(), constrainedElement.getConstraints() ) );
isCascading = isCascading || constrainedElement.isCascading();
unwrapMode = constrainedElement.unwrapMode();

Expand Down Expand Up @@ -153,7 +154,7 @@ private <A extends Annotation> MetaConstraint<A> adaptOriginAndImplicitGroup(Met

Class<?> constraintClass = constraint.getLocation().getDeclaringClass();

ConstraintDescriptorImpl<A> descriptor = new ConstraintDescriptorImpl<A>(
ConstraintDescriptorImpl<A> descriptor = new ConstraintDescriptorImpl<>(
constraintHelper,
constraint.getLocation().getMember(),
constraint.getDescriptor().getAnnotation(),
Expand All @@ -163,12 +164,19 @@ private <A extends Annotation> MetaConstraint<A> adaptOriginAndImplicitGroup(Met
constraint.getDescriptor().getConstraintType()
);

return new MetaConstraint<A>(
return new MetaConstraint<>(
descriptor,
constraint.getLocation()
);
}

/**
* Allows specific sub-classes to customize the retrieved constraints.
*/
protected Set<MetaConstraint<?>> adaptConstraints(ConstrainedElementKind constrainedElementKind, Set<MetaConstraint<?>> constraints) {
return constraints;
}

/**
* @param rootClass The root class. That is the class for which we currently
* create a {@code BeanMetaData}
Expand Down
Expand Up @@ -22,6 +22,7 @@
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import javax.validation.ElementKind;
import javax.validation.metadata.GroupConversionDescriptor;
Expand All @@ -32,6 +33,7 @@
import org.hibernate.validator.internal.metadata.core.MetaConstraint;
import org.hibernate.validator.internal.metadata.descriptor.PropertyDescriptorImpl;
import org.hibernate.validator.internal.metadata.facets.Cascadable;
import org.hibernate.validator.internal.metadata.location.ConstraintLocation;
import org.hibernate.validator.internal.metadata.raw.ConstrainedElement;
import org.hibernate.validator.internal.metadata.raw.ConstrainedElement.ConstrainedElementKind;
import org.hibernate.validator.internal.metadata.raw.ConstrainedExecutable;
Expand Down Expand Up @@ -317,6 +319,18 @@ else if ( constrainedElement.getKind() == ConstrainedElementKind.METHOD ) {
}
}

@Override
protected Set<MetaConstraint<?>> adaptConstraints(ConstrainedElementKind kind, Set<MetaConstraint<?>> constraints) {
if ( kind == ConstrainedElementKind.FIELD || kind == ConstrainedElementKind.TYPE ) {
return constraints;
}

// convert (getter) return value locations into property locations for usage within this meta-data
return constraints.stream()
.map( c -> new MetaConstraint<>( c.getDescriptor(), ConstraintLocation.forProperty( c.getLocation().getMember() ) ) )
.collect( Collectors.toSet() );
}

private String getPropertyName(ConstrainedElement constrainedElement) {
if ( constrainedElement.getKind() == ConstrainedElementKind.FIELD ) {
return ReflectionHelper.getPropertyName( ( (ConstrainedField) constrainedElement ).getField() );
Expand Down

0 comments on commit 91e782b

Please sign in to comment.