Skip to content

Commit da77077

Browse files
committed
WIP
1 parent bf7b5c0 commit da77077

25 files changed

+507
-479
lines changed

engine/src/main/java/org/hibernate/validator/internal/engine/ValidationContext.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorContextImpl;
3131
import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorManager;
3232
import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintViolationCreationContext;
33+
import org.hibernate.validator.internal.engine.path.PathBuilder;
3334
import org.hibernate.validator.internal.engine.path.PathImpl;
3435
import org.hibernate.validator.internal.metadata.BeanMetaDataManager;
3536
import org.hibernate.validator.internal.metadata.aggregated.BeanMetaData;
@@ -285,7 +286,7 @@ public ConstraintViolation<T> createConstraintViolation(ValueContext<?, ?> local
285286
constraintViolationCreationContext.getExpressionVariables()
286287
);
287288
// at this point we make a copy of the path to avoid side effects
288-
Path path = PathImpl.createCopy( constraintViolationCreationContext.getPath() );
289+
Path path = constraintViolationCreationContext.getPath().build();
289290
Object dynamicPayload = constraintViolationCreationContext.getDynamicPayload();
290291
if ( executableParameters != null ) {
291292
return ConstraintViolationImpl.forParameterValidation(
@@ -426,10 +427,10 @@ private boolean isAlreadyValidatedForCurrentGroup(Object value, Class<?> group)
426427
return processedUnits.contains( new BeanGroupProcessedUnit( value, group ) );
427428
}
428429

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

435436
private void markCurrentBeanAsProcessedForCurrentGroup(Object bean, Class<?> group) {

engine/src/main/java/org/hibernate/validator/internal/engine/ValidatorImpl.java

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,15 @@
3737
import javax.validation.valueextraction.ValueExtractor;
3838

3939
import org.hibernate.validator.internal.engine.ValidationContext.ValidationContextBuilder;
40+
import org.hibernate.validator.internal.engine.ValueContext.ValueState;
4041
import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorManager;
4142
import org.hibernate.validator.internal.engine.groups.Group;
4243
import org.hibernate.validator.internal.engine.groups.GroupWithInheritance;
4344
import org.hibernate.validator.internal.engine.groups.Sequence;
4445
import org.hibernate.validator.internal.engine.groups.ValidationOrder;
4546
import org.hibernate.validator.internal.engine.groups.ValidationOrderGenerator;
4647
import org.hibernate.validator.internal.engine.path.NodeImpl;
47-
import org.hibernate.validator.internal.engine.path.PathImpl;
48+
import org.hibernate.validator.internal.engine.path.PathBuilder;
4849
import org.hibernate.validator.internal.engine.resolver.CachingTraversableResolverForSingleValidation;
4950
import org.hibernate.validator.internal.engine.valueextraction.ValueExtractorDescriptor;
5051
import org.hibernate.validator.internal.engine.valueextraction.ValueExtractorHelper;
@@ -177,7 +178,7 @@ public final <T> Set<ConstraintViolation<T>> validate(T object, Class<?>... grou
177178
parameterNameProvider,
178179
object,
179180
validationContext.getRootBeanMetaData(),
180-
PathImpl.createRootPath()
181+
PathBuilder.createRootPath()
181182
);
182183

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

198-
PathImpl propertyPath = PathImpl.createPathFromString( propertyName );
199+
PathBuilder propertyPath = PathBuilder.createPathFromString( propertyName );
199200
ValueContext<?, Object> valueContext = getValueContextForPropertyValidation( validationContext, propertyPath );
200201

201202
if ( valueContext.getCurrentBean() == null ) {
@@ -224,7 +225,7 @@ public final <T> Set<ConstraintViolation<T>> validateValue(Class<T> beanType, St
224225
return validateValueInContext(
225226
validationContext,
226227
value,
227-
PathImpl.createPathFromString( propertyName ),
228+
PathBuilder.createPathFromString( propertyName ),
228229
validationOrder
229230
);
230231
}
@@ -551,11 +552,11 @@ private boolean validateMetaConstraint(ValidationContext<?> validationContext, V
551552

552553
success = metaConstraint.validateConstraint( validationContext, valueContext );
553554

554-
validationContext.markConstraintProcessed( valueContext.getCurrentBean(), valueContext.getPropertyPath(), metaConstraint );
555+
validationContext.markConstraintProcessed( valueContext.getCurrentBean(), valueContext.getPropertyPath().build(), metaConstraint );
555556
}
556557

557558
// reset the value context to the state before this call
558-
valueContext.resetValueState( originalValueState );
559+
valueContext.resetValueState( originalValueState, true );
559560

560561
return success;
561562
}
@@ -600,13 +601,13 @@ private void validateCascadedConstraints(ValidationContext<?> validationContext,
600601
}
601602

602603
// reset the value context
603-
valueContext.resetValueState( originalValueState );
604+
valueContext.resetValueState( originalValueState, true );
604605
}
605606
}
606607

607608
private void validateCascadedAnnotatedObjectForCurrentGroup(Object value, ValidationContext<?> validationContext, ValueContext<?, Object> valueContext,
608609
CascadingMetaData cascadingMetaData) {
609-
if ( validationContext.isBeanAlreadyValidated( value, valueContext.getCurrentGroup(), valueContext.getPropertyPath() ) ||
610+
if ( validationContext.isBeanAlreadyValidated( value, valueContext.getCurrentGroup(), valueContext.getPropertyPath().build() ) ||
610611
shouldFailFast( validationContext ) ) {
611612
return;
612613
}
@@ -682,7 +683,7 @@ public void keyedValue(String nodeName, Object key, Object value) {
682683

683684
private void doValidate(Object value, String nodeName) {
684685
if ( value == null ||
685-
validationContext.isBeanAlreadyValidated( value, valueContext.getCurrentGroup(), valueContext.getPropertyPath() ) ||
686+
validationContext.isBeanAlreadyValidated( value, valueContext.getCurrentGroup(), valueContext.getPropertyPath().build() ) ||
686687
shouldFailFast( validationContext ) ) {
687688
return;
688689
}
@@ -713,11 +714,15 @@ private void doValidate(Object value, String nodeName) {
713714
cascadedValueContext.setTypeParameter( cascadingMetaData.getDeclaredContainerClass(), cascadingMetaData.getDeclaredTypeParameter() );
714715
}
715716

717+
ValueState<Object> valueState = cascadedTypeArgumentValueContext.getCurrentValueState();
718+
716719
if ( nodeName != null ) {
717720
cascadedTypeArgumentValueContext.appendTypeParameterNode( nodeName );
718721
}
719722

720723
validateCascadedContainerElementsInContext( value, validationContext, cascadedTypeArgumentValueContext, cascadingMetaData, validationOrder );
724+
725+
cascadedTypeArgumentValueContext.resetValueState( valueState, nodeName != null );
721726
}
722727
}
723728
}
@@ -780,7 +785,7 @@ private ValueContext<?, Object> buildNewLocalExecutionContext(ValueContext<?, ?>
780785
return newValueContext;
781786
}
782787

783-
private <T> Set<ConstraintViolation<T>> validateValueInContext(ValidationContext<T> validationContext, Object value, PathImpl propertyPath,
788+
private <T> Set<ConstraintViolation<T>> validateValueInContext(ValidationContext<T> validationContext, Object value, PathBuilder propertyPath,
784789
ValidationOrder validationOrder) {
785790
ValueContext<?, Object> valueContext = getValueContextForValueValidation( validationContext, propertyPath );
786791
valueContext.setCurrentValidatedValue( value );
@@ -868,7 +873,7 @@ private <T> void validateParametersInContext(ValidationContext<T> validationCont
868873
parameterNameProvider,
869874
parameterValues,
870875
executableMetaData.getValidatableParametersMetaData(),
871-
PathImpl.createPathForExecutable( executableMetaData )
876+
PathBuilder.createPathForExecutable( executableMetaData )
872877
);
873878

874879
groupIterator = validationOrder.getGroupIterator();
@@ -1002,7 +1007,7 @@ private <T> ValueContext<T, Object> getExecutableValueContext(T object, Executab
10021007
parameterNameProvider,
10031008
object,
10041009
validatable,
1005-
PathImpl.createPathForExecutable( executableMetaData )
1010+
PathBuilder.createPathForExecutable( executableMetaData )
10061011
);
10071012
}
10081013
else {
@@ -1011,7 +1016,7 @@ private <T> ValueContext<T, Object> getExecutableValueContext(T object, Executab
10111016
parameterNameProvider,
10121017
(Class<T>) null, //the type is not required in this case (only for cascaded validation)
10131018
validatable,
1014-
PathImpl.createPathForExecutable( executableMetaData )
1019+
PathBuilder.createPathForExecutable( executableMetaData )
10151020
);
10161021
}
10171022

@@ -1054,7 +1059,7 @@ private <V, T> void validateReturnValueInContext(ValidationContext<T> validation
10541059
parameterNameProvider,
10551060
value,
10561061
executableMetaData.getReturnValueMetaData(),
1057-
PathImpl.createPathForExecutable( executableMetaData )
1062+
PathBuilder.createPathForExecutable( executableMetaData )
10581063
);
10591064

10601065
groupIterator = validationOrder.getGroupIterator();
@@ -1159,7 +1164,7 @@ private <T> void validateReturnValueForSingleGroup(ValidationContext<T> validati
11591164
* @return Returns an instance of {@code ValueContext} which describes the local validation context associated to
11601165
* the given property path.
11611166
*/
1162-
private <V> ValueContext<?, V> getValueContextForPropertyValidation(ValidationContext<?> validationContext, PathImpl propertyPath) {
1167+
private <V> ValueContext<?, V> getValueContextForPropertyValidation(ValidationContext<?> validationContext, PathBuilder propertyPath) {
11631168
Class<?> clazz = validationContext.getRootBeanClass();
11641169
BeanMetaData<?> beanMetaData = validationContext.getRootBeanMetaData();
11651170
Object value = validationContext.getRootBean();
@@ -1237,7 +1242,7 @@ else if ( propertyPathNode.getKey() != null ) {
12371242
* the given property path.
12381243
*/
12391244
private <V> ValueContext<?, V> getValueContextForValueValidation(ValidationContext<?> validationContext,
1240-
PathImpl propertyPath) {
1245+
PathBuilder propertyPath) {
12411246
Class<?> clazz = validationContext.getRootBeanClass();
12421247
BeanMetaData<?> beanMetaData = null;
12431248
PropertyMetaData propertyMetaData = null;
@@ -1298,7 +1303,7 @@ private boolean isValidationRequired(ValidationContext<?> validationContext,
12981303
}
12991304
if ( validationContext.hasMetaConstraintBeenProcessed(
13001305
valueContext.getCurrentBean(),
1301-
valueContext.getPropertyPath(),
1306+
valueContext.getPropertyPath().build(),
13021307
metaConstraint
13031308
) ) {
13041309
return false;
@@ -1315,7 +1320,7 @@ private boolean isValidationRequired(ValidationContext<?> validationContext,
13151320
);
13161321
}
13171322

1318-
private boolean isReachable(ValidationContext<?> validationContext, Object traversableObject, PathImpl path, ElementType type) {
1323+
private boolean isReachable(ValidationContext<?> validationContext, Object traversableObject, PathBuilder path, ElementType type) {
13191324
if ( needToCallTraversableResolver( path, type ) ) {
13201325
return true;
13211326
}
@@ -1335,7 +1340,7 @@ private boolean isReachable(ValidationContext<?> validationContext, Object trave
13351340
}
13361341
}
13371342

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

1349-
private boolean isCascadeRequired(ValidationContext<?> validationContext, Object traversableObject, PathImpl path, ElementType type) {
1354+
private boolean isCascadeRequired(ValidationContext<?> validationContext, Object traversableObject, PathBuilder path, ElementType type) {
13501355
if ( needToCallTraversableResolver( path, type ) ) {
13511356
return true;
13521357
}
@@ -1375,15 +1380,15 @@ private boolean isClassLevelConstraint(ElementType type) {
13751380
return ElementType.TYPE.equals( type );
13761381
}
13771382

1378-
private boolean isCrossParameterValidation(PathImpl path) {
1383+
private boolean isCrossParameterValidation(PathBuilder path) {
13791384
return path.getLeafNode().getKind() == ElementKind.CROSS_PARAMETER;
13801385
}
13811386

1382-
private boolean isParameterValidation(PathImpl path) {
1387+
private boolean isParameterValidation(PathBuilder path) {
13831388
return path.getLeafNode().getKind() == ElementKind.PARAMETER;
13841389
}
13851390

1386-
private boolean isReturnValueValidation(PathImpl path) {
1391+
private boolean isReturnValueValidation(PathBuilder path) {
13871392
return path.getLeafNode().getKind() == ElementKind.RETURN_VALUE;
13881393
}
13891394

engine/src/main/java/org/hibernate/validator/internal/engine/ValueContext.java

Lines changed: 17 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
import javax.validation.groups.Default;
1313

14-
import org.hibernate.validator.internal.engine.path.PathImpl;
14+
import org.hibernate.validator.internal.engine.path.PathBuilder;
1515
import org.hibernate.validator.internal.engine.valueextraction.AnnotatedObject;
1616
import org.hibernate.validator.internal.engine.valueextraction.ArrayElement;
1717
import org.hibernate.validator.internal.metadata.BeanMetaDataManager;
@@ -52,7 +52,7 @@ public class ValueContext<T, V> {
5252
/**
5353
* The current property path we are validating.
5454
*/
55-
private PathImpl propertyPath;
55+
private final PathBuilder propertyPath;
5656

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

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

8181
@SuppressWarnings("unchecked")
8282
public static <T, V> ValueContext<T, V> getLocalExecutionContext(ExecutableParameterNameProvider parameterNameProvider, T value,
83-
BeanMetaData<?> currentBeanMetaData, PathImpl propertyPath) {
83+
BeanMetaData<?> currentBeanMetaData, PathBuilder propertyPath) {
8484
Class<T> rootBeanType = (Class<T>) value.getClass();
8585
return new ValueContext<>( parameterNameProvider, value, rootBeanType, (BeanMetaData<T>) currentBeanMetaData, currentBeanMetaData, propertyPath );
8686
}
8787

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

9494
@SuppressWarnings("unchecked")
9595
public static <T, V> ValueContext<T, V> getLocalExecutionContext(ExecutableParameterNameProvider parameterNameProvider, Class<T> currentBeanType,
96-
BeanMetaData<?> currentBeanMetaData, PathImpl propertyPath) {
96+
BeanMetaData<?> currentBeanMetaData, PathBuilder propertyPath) {
9797
return new ValueContext<>( parameterNameProvider, null, currentBeanType, (BeanMetaData<T>) currentBeanMetaData, currentBeanMetaData, propertyPath );
9898
}
9999

100-
private ValueContext(ExecutableParameterNameProvider parameterNameProvider, T currentBean, Class<T> currentBeanType, BeanMetaData<T> currentBeanMetaData, Validatable validatable, PathImpl propertyPath) {
100+
private ValueContext(ExecutableParameterNameProvider parameterNameProvider, T currentBean, Class<T> currentBeanType, BeanMetaData<T> currentBeanMetaData, Validatable validatable, PathBuilder propertyPath) {
101101
this.parameterNameProvider = parameterNameProvider;
102102
this.currentBean = currentBean;
103103
this.currentBeanType = currentBeanType;
@@ -106,7 +106,7 @@ private ValueContext(ExecutableParameterNameProvider parameterNameProvider, T cu
106106
this.propertyPath = propertyPath;
107107
}
108108

109-
public final PathImpl getPropertyPath() {
109+
public final PathBuilder getPropertyPath() {
110110
return propertyPath;
111111
}
112112

@@ -138,21 +138,15 @@ public final Object getCurrentValidatedValue() {
138138
}
139139

140140
public final void appendNode(Cascadable node) {
141-
PathImpl newPath = PathImpl.createCopy( propertyPath );
142-
node.appendTo( newPath );
143-
propertyPath = newPath;
141+
node.appendTo( propertyPath );
144142
}
145143

146144
public final void appendNode(ConstraintLocation location) {
147-
PathImpl newPath = PathImpl.createCopy( propertyPath );
148-
location.appendTo( parameterNameProvider, newPath );
149-
propertyPath = newPath;
145+
location.appendTo( parameterNameProvider, propertyPath );
150146
}
151147

152148
public final void appendTypeParameterNode(String nodeName) {
153-
PathImpl newPath = PathImpl.createCopy( propertyPath );
154-
newPath.addContainerElementNode( nodeName );
155-
propertyPath = newPath;
149+
propertyPath.addContainerElementNode( nodeName );
156150
}
157151

158152
public final void markCurrentPropertyAsIterable() {
@@ -209,11 +203,13 @@ public final void setElementType(ElementType elementType) {
209203
}
210204

211205
public final ValueState<V> getCurrentValueState() {
212-
return new ValueState<V>( propertyPath, currentValue );
206+
return new ValueState<>( currentValue );
213207
}
214208

215-
public final void resetValueState(ValueState<V> valueState) {
216-
this.propertyPath = valueState.propertyPath;
209+
public final void resetValueState(ValueState<V> valueState, boolean resetPath) {
210+
if ( resetPath ) {
211+
this.propertyPath.removeLeafNode();
212+
}
217213
this.currentValue = valueState.currentValue;
218214
}
219215

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

239235
public static class ValueState<V> {
240236

241-
private final PathImpl propertyPath;
242-
243237
private final V currentValue;
244238

245-
private ValueState(PathImpl propertyPath, V currentValue) {
246-
this.propertyPath = propertyPath;
239+
private ValueState(V currentValue) {
247240
this.currentValue = currentValue;
248241
}
249242
}

0 commit comments

Comments
 (0)