Skip to content

Commit 9a786a5

Browse files
committed
HV-1831 Make path fully modifiable
make it more of a builder and do not recreate nodes whenever possible Signed-off-by: marko-bekhta <[email protected]>
1 parent 96dff32 commit 9a786a5

File tree

56 files changed

+861
-510
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+861
-510
lines changed

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

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@
3838
import org.hibernate.validator.internal.engine.groups.Sequence;
3939
import org.hibernate.validator.internal.engine.groups.ValidationOrder;
4040
import org.hibernate.validator.internal.engine.groups.ValidationOrderGenerator;
41-
import org.hibernate.validator.internal.engine.path.ModifiablePath;
42-
import org.hibernate.validator.internal.engine.path.NodeImpl;
41+
import org.hibernate.validator.internal.engine.path.MutableNode;
42+
import org.hibernate.validator.internal.engine.path.MutablePath;
4343
import org.hibernate.validator.internal.engine.resolver.TraversableResolvers;
4444
import org.hibernate.validator.internal.engine.validationcontext.BaseBeanValidationContext;
4545
import org.hibernate.validator.internal.engine.validationcontext.ExecutableValidationContext;
@@ -164,7 +164,7 @@ public final <T> Set<ConstraintViolation<T>> validate(T object, Class<?>... grou
164164
validatorScopedContext.getParameterNameProvider(),
165165
object,
166166
validationContext.getRootBeanMetaData(),
167-
ModifiablePath.createRootPath()
167+
MutablePath.createRootPath()
168168
);
169169

170170
return validateInContext( validationContext, valueContext, validationOrder );
@@ -184,7 +184,7 @@ public final <T> Set<ConstraintViolation<T>> validateProperty(T object, String p
184184
return Collections.emptySet();
185185
}
186186

187-
ModifiablePath propertyPath = ModifiablePath.createPathFromString( propertyName );
187+
MutablePath propertyPath = MutablePath.createPathFromString( propertyName );
188188
BaseBeanValidationContext<T> validationContext = getValidationContextBuilder().forValidateProperty( rootBeanClass, rootBeanMetaData, object,
189189
propertyPath );
190190

@@ -211,7 +211,7 @@ public final <T> Set<ConstraintViolation<T>> validateValue(Class<T> beanType, St
211211
return Collections.emptySet();
212212
}
213213

214-
ModifiablePath propertyPath = ModifiablePath.createPathFromString( propertyName );
214+
MutablePath propertyPath = MutablePath.createPathFromString( propertyName );
215215
BaseBeanValidationContext<T> validationContext = getValidationContextBuilder().forValidateValue( beanType, rootBeanMetaData, propertyPath );
216216

217217
ValidationOrder validationOrder = determineGroupValidationOrder( groups );
@@ -814,7 +814,7 @@ private BeanValueContext<?, Object> buildNewLocalExecutionContext(ValueContext<?
814814
return newValueContext;
815815
}
816816

817-
private <T> Set<ConstraintViolation<T>> validateValueInContext(BaseBeanValidationContext<T> validationContext, Object value, ModifiablePath propertyPath,
817+
private <T> Set<ConstraintViolation<T>> validateValueInContext(BaseBeanValidationContext<T> validationContext, Object value, MutablePath propertyPath,
818818
ValidationOrder validationOrder) {
819819
BeanValueContext<?, Object> valueContext = getValueContextForValueValidation( validationContext.getRootBeanClass(), propertyPath );
820820
valueContext.setCurrentValidatedValue( value );
@@ -903,7 +903,7 @@ private <T> void validateParametersInContext(ExecutableValidationContext<T> vali
903903
validatorScopedContext.getParameterNameProvider(),
904904
parameterValues,
905905
executableMetaData.getValidatableParametersMetaData(),
906-
ModifiablePath.createPathForExecutable( executableMetaData )
906+
MutablePath.createPathForExecutable( executableMetaData )
907907
);
908908

909909
groupIterator = validationOrder.getGroupIterator();
@@ -1036,7 +1036,7 @@ private <T> ValueContext<T, Object> getExecutableValueContext(T object, Executab
10361036
validatorScopedContext.getParameterNameProvider(),
10371037
object,
10381038
validatable,
1039-
ModifiablePath.createPathForExecutable( executableMetaData )
1039+
MutablePath.createPathForExecutable( executableMetaData )
10401040
);
10411041

10421042
valueContext.setCurrentGroup( group );
@@ -1079,7 +1079,7 @@ private <V, T> void validateReturnValueInContext(ExecutableValidationContext<T>
10791079
validatorScopedContext.getParameterNameProvider(),
10801080
value,
10811081
executableMetaData.getReturnValueMetaData(),
1082-
ModifiablePath.createPathForExecutable( executableMetaData )
1082+
MutablePath.createPathForExecutable( executableMetaData )
10831083
);
10841084

10851085
groupIterator = validationOrder.getGroupIterator();
@@ -1185,7 +1185,7 @@ private <T> void validateReturnValueForSingleGroup(BaseBeanValidationContext<T>
11851185
* @return Returns an instance of {@code ValueContext} which describes the local validation context associated to
11861186
* the given property path.
11871187
*/
1188-
private <V> BeanValueContext<?, V> getValueContextForPropertyValidation(BaseBeanValidationContext<?> validationContext, ModifiablePath propertyPath) {
1188+
private <V> BeanValueContext<?, V> getValueContextForPropertyValidation(BaseBeanValidationContext<?> validationContext, MutablePath propertyPath) {
11891189
Class<?> clazz = validationContext.getRootBeanClass();
11901190
BeanMetaData<?> beanMetaData = validationContext.getRootBeanMetaData();
11911191
Object value = validationContext.getRootBean();
@@ -1195,7 +1195,7 @@ private <V> BeanValueContext<?, V> getValueContextForPropertyValidation(BaseBean
11951195

11961196
while ( propertyPathIter.hasNext() ) {
11971197
// cast is ok, since we are dealing with engine internal classes
1198-
NodeImpl propertyPathNode = (NodeImpl) propertyPathIter.next();
1198+
MutableNode propertyPathNode = (MutableNode) propertyPathIter.next();
11991199
propertyMetaData = getBeanPropertyMetaData( beanMetaData, propertyPathNode );
12001200

12011201
// if the property is not the leaf property, we set up the context for the next iteration
@@ -1214,7 +1214,7 @@ private <V> BeanValueContext<?, V> getValueContextForPropertyValidation(BaseBean
12141214
// if we are in the case of an iterable and we want to validate an element of this iterable, we have to get the
12151215
// element value
12161216
if ( propertyPathNode.isIterable() ) {
1217-
propertyPathNode = (NodeImpl) propertyPathIter.next();
1217+
propertyPathNode = (MutableNode) propertyPathIter.next();
12181218

12191219
if ( propertyPathNode.getIndex() != null ) {
12201220
value = ReflectionHelper.getIndexedValue( value, propertyPathNode.getIndex() );
@@ -1263,7 +1263,7 @@ else if ( propertyPathNode.getKey() != null ) {
12631263
* the given property path.
12641264
*/
12651265
private <V> BeanValueContext<?, V> getValueContextForValueValidation(Class<?> rootBeanClass,
1266-
ModifiablePath propertyPath) {
1266+
MutablePath propertyPath) {
12671267
Class<?> clazz = rootBeanClass;
12681268
BeanMetaData<?> beanMetaData = null;
12691269
PropertyMetaData propertyMetaData = null;
@@ -1272,7 +1272,7 @@ private <V> BeanValueContext<?, V> getValueContextForValueValidation(Class<?> ro
12721272

12731273
while ( propertyPathIter.hasNext() ) {
12741274
// cast is ok, since we are dealing with engine internal classes
1275-
NodeImpl propertyPathNode = (NodeImpl) propertyPathIter.next();
1275+
MutableNode propertyPathNode = (MutableNode) propertyPathIter.next();
12761276
beanMetaData = beanMetaDataManager.getBeanMetaData( clazz );
12771277
propertyMetaData = getBeanPropertyMetaData( beanMetaData, propertyPathNode );
12781278

@@ -1281,7 +1281,7 @@ private <V> BeanValueContext<?, V> getValueContextForValueValidation(Class<?> ro
12811281
// if we are in the case of an iterable and we want to validate an element of this iterable, we have to get the
12821282
// type from the parameterized type
12831283
if ( propertyPathNode.isIterable() ) {
1284-
propertyPathNode = (NodeImpl) propertyPathIter.next();
1284+
propertyPathNode = (MutableNode) propertyPathIter.next();
12851285

12861286
clazz = ReflectionHelper.getClassFromType( ReflectionHelper.getCollectionElementType( propertyMetaData.getType() ) );
12871287
beanMetaData = beanMetaDataManager.getBeanMetaData( clazz );
@@ -1330,13 +1330,13 @@ private boolean isValidationRequired(BaseBeanValidationContext<?> validationCont
13301330
);
13311331
}
13321332

1333-
private boolean isReachable(BaseBeanValidationContext<?> validationContext, Object traversableObject, ModifiablePath path,
1333+
private boolean isReachable(BaseBeanValidationContext<?> validationContext, Object traversableObject, MutablePath path,
13341334
ConstraintLocationKind constraintLocationKind) {
13351335
if ( needToCallTraversableResolver( path, constraintLocationKind ) ) {
13361336
return true;
13371337
}
13381338

1339-
Path pathToObject = ModifiablePath.createCopyWithoutLeafNode( path );
1339+
Path pathToObject = MutablePath.createCopyWithoutLeafNode( path );
13401340
try {
13411341
return validationContext.getTraversableResolver().isReachable(
13421342
traversableObject,
@@ -1351,7 +1351,7 @@ private boolean isReachable(BaseBeanValidationContext<?> validationContext, Obje
13511351
}
13521352
}
13531353

1354-
private boolean needToCallTraversableResolver(ModifiablePath path, ConstraintLocationKind constraintLocationKind) {
1354+
private boolean needToCallTraversableResolver(MutablePath path, ConstraintLocationKind constraintLocationKind) {
13551355
// as the TraversableResolver interface is designed right now it does not make sense to call it when
13561356
// there is no traversable object hosting the property to be accessed. For this reason we don't call the resolver
13571357
// for class level constraints (ElementType.TYPE) or top level method parameters or return values.
@@ -1362,7 +1362,7 @@ private boolean needToCallTraversableResolver(ModifiablePath path, ConstraintLoc
13621362
|| isReturnValueValidation( path );
13631363
}
13641364

1365-
private boolean isCascadeRequired(BaseBeanValidationContext<?> validationContext, Object traversableObject, ModifiablePath path,
1365+
private boolean isCascadeRequired(BaseBeanValidationContext<?> validationContext, Object traversableObject, MutablePath path,
13661366
ConstraintLocationKind constraintLocationKind) {
13671367
if ( needToCallTraversableResolver( path, constraintLocationKind ) ) {
13681368
return true;
@@ -1373,7 +1373,7 @@ private boolean isCascadeRequired(BaseBeanValidationContext<?> validationContext
13731373
return false;
13741374
}
13751375

1376-
Path pathToObject = ModifiablePath.createCopyWithoutLeafNode( path );
1376+
Path pathToObject = MutablePath.createCopyWithoutLeafNode( path );
13771377
try {
13781378
return validationContext.getTraversableResolver().isCascadable(
13791379
traversableObject,
@@ -1392,15 +1392,15 @@ private boolean isClassLevelConstraint(ConstraintLocationKind constraintLocation
13921392
return ConstraintLocationKind.TYPE.equals( constraintLocationKind );
13931393
}
13941394

1395-
private boolean isCrossParameterValidation(ModifiablePath path) {
1395+
private boolean isCrossParameterValidation(MutablePath path) {
13961396
return path.getLeafNode().getKind() == ElementKind.CROSS_PARAMETER;
13971397
}
13981398

1399-
private boolean isParameterValidation(ModifiablePath path) {
1399+
private boolean isParameterValidation(MutablePath path) {
14001400
return path.getLeafNode().getKind() == ElementKind.PARAMETER;
14011401
}
14021402

1403-
private boolean isReturnValueValidation(ModifiablePath path) {
1403+
private boolean isReturnValueValidation(MutablePath path) {
14041404
return path.getLeafNode().getKind() == ElementKind.RETURN_VALUE;
14051405
}
14061406

engine/src/main/java/org/hibernate/validator/internal/engine/constraintvalidation/ConstraintValidatorContextImpl.java

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828

2929
import org.hibernate.validator.constraintvalidation.HibernateConstraintValidatorContext;
3030
import org.hibernate.validator.constraintvalidation.HibernateConstraintViolationBuilder;
31-
import org.hibernate.validator.internal.engine.path.ModifiablePath;
31+
import org.hibernate.validator.internal.engine.path.MutablePath;
3232
import org.hibernate.validator.internal.util.CollectionHelper;
3333
import org.hibernate.validator.internal.util.Contracts;
3434
import org.hibernate.validator.internal.util.logging.Log;
@@ -49,7 +49,7 @@ public class ConstraintValidatorContextImpl implements HibernateConstraintValida
4949
private final ClockProvider clockProvider;
5050
private final ExpressionLanguageFeatureLevel defaultConstraintExpressionLanguageFeatureLevel;
5151
private final ExpressionLanguageFeatureLevel defaultCustomViolationExpressionLanguageFeatureLevel;
52-
private final ModifiablePath basePath;
52+
private final MutablePath basePath;
5353
private final ConstraintDescriptor<?> constraintDescriptor;
5454
private List<ConstraintViolationCreationContext> constraintViolationCreationContexts;
5555
private boolean defaultDisabled;
@@ -58,7 +58,7 @@ public class ConstraintValidatorContextImpl implements HibernateConstraintValida
5858

5959
public ConstraintValidatorContextImpl(
6060
ClockProvider clockProvider,
61-
ModifiablePath propertyPath,
61+
MutablePath propertyPath,
6262
ConstraintDescriptor<?> constraintDescriptor,
6363
Object constraintValidatorPayload,
6464
ExpressionLanguageFeatureLevel defaultConstraintExpressionLanguageFeatureLevel,
@@ -168,8 +168,8 @@ public final List<ConstraintViolationCreationContext> getConstraintViolationCrea
168168
return CollectionHelper.toImmutableList( returnedConstraintViolationCreationContexts );
169169
}
170170

171-
protected final ModifiablePath getCopyOfBasePath() {
172-
return ModifiablePath.createCopy( basePath );
171+
protected final MutablePath getCopyOfBasePath() {
172+
return MutablePath.createCopy( basePath );
173173
}
174174

175175
private ConstraintViolationCreationContext getDefaultConstraintViolationCreationContext() {
@@ -188,13 +188,13 @@ private abstract class NodeBuilderBase {
188188

189189
protected final String messageTemplate;
190190
protected ExpressionLanguageFeatureLevel expressionLanguageFeatureLevel;
191-
protected ModifiablePath propertyPath;
191+
protected MutablePath propertyPath;
192192

193-
protected NodeBuilderBase(String template, ModifiablePath path) {
193+
protected NodeBuilderBase(String template, MutablePath path) {
194194
this( template, defaultCustomViolationExpressionLanguageFeatureLevel, path );
195195
}
196196

197-
protected NodeBuilderBase(String template, ExpressionLanguageFeatureLevel expressionLanguageFeatureLevel, ModifiablePath path) {
197+
protected NodeBuilderBase(String template, ExpressionLanguageFeatureLevel expressionLanguageFeatureLevel, MutablePath path) {
198198
this.messageTemplate = template;
199199
this.expressionLanguageFeatureLevel = expressionLanguageFeatureLevel;
200200
this.propertyPath = path;
@@ -225,7 +225,7 @@ public ConstraintValidatorContext addConstraintViolation() {
225225

226226
protected class ConstraintViolationBuilderImpl extends NodeBuilderBase implements HibernateConstraintViolationBuilder {
227227

228-
protected ConstraintViolationBuilderImpl(String template, ModifiablePath path) {
228+
protected ConstraintViolationBuilderImpl(String template, MutablePath path) {
229229
super( template, path );
230230
}
231231

@@ -274,15 +274,19 @@ public ContainerElementNodeBuilderCustomizableContext addContainerElementNode(St
274274
*/
275275
private void dropLeafNodeIfRequired() {
276276
if ( propertyPath.getLeafNode().getKind() == ElementKind.BEAN ) {
277-
propertyPath = ModifiablePath.createCopyWithoutLeafNode( propertyPath );
277+
propertyPath = MutablePath.createCopyWithoutLeafNode( propertyPath );
278+
}
279+
else {
280+
// if we haven't dropped the node, we should clean up "container-related" things:
281+
propertyPath.getLeafNode().reset();
278282
}
279283
}
280284
}
281285

282286
protected class NodeBuilder extends NodeBuilderBase
283287
implements NodeBuilderDefinedContext, LeafNodeBuilderDefinedContext, ContainerElementNodeBuilderDefinedContext {
284288

285-
protected NodeBuilder(String template, ExpressionLanguageFeatureLevel expressionLanguageFeatureLevel, ModifiablePath path) {
289+
protected NodeBuilder(String template, ExpressionLanguageFeatureLevel expressionLanguageFeatureLevel, MutablePath path) {
286290
super( template, expressionLanguageFeatureLevel, path );
287291
}
288292

@@ -322,7 +326,7 @@ private class DeferredNodeBuilder extends NodeBuilderBase
322326

323327
private DeferredNodeBuilder(String template,
324328
ExpressionLanguageFeatureLevel expressionLanguageFeatureLevel,
325-
ModifiablePath path,
329+
MutablePath path,
326330
String nodeName,
327331
ElementKind leafNodeKind) {
328332
super( template, expressionLanguageFeatureLevel, path );
@@ -334,7 +338,7 @@ private DeferredNodeBuilder(String template,
334338

335339
private DeferredNodeBuilder(String template,
336340
ExpressionLanguageFeatureLevel expressionLanguageFeatureLevel,
337-
ModifiablePath path,
341+
MutablePath path,
338342
String nodeName,
339343
Class<?> leafNodeContainerType,
340344
Integer leafNodeTypeArgumentIndex) {

engine/src/main/java/org/hibernate/validator/internal/engine/constraintvalidation/ConstraintViolationCreationContext.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88

99
import java.util.Map;
1010

11-
import org.hibernate.validator.internal.engine.path.ModifiablePath;
11+
import jakarta.validation.Path;
12+
13+
import org.hibernate.validator.internal.engine.path.MutablePath;
1214
import org.hibernate.validator.internal.util.stereotypes.Immutable;
1315
import org.hibernate.validator.messageinterpolation.ExpressionLanguageFeatureLevel;
1416

@@ -23,7 +25,7 @@ public class ConstraintViolationCreationContext {
2325
private final String message;
2426
private final ExpressionLanguageFeatureLevel expressionLanguageFeatureLevel;
2527
private final boolean customViolation;
26-
private final ModifiablePath propertyPath;
28+
private final Path propertyPath;
2729
@Immutable
2830
private final Map<String, Object> messageParameters;
2931
@Immutable
@@ -33,14 +35,15 @@ public class ConstraintViolationCreationContext {
3335
public ConstraintViolationCreationContext(String message,
3436
ExpressionLanguageFeatureLevel expressionLanguageFeatureLevel,
3537
boolean customViolation,
36-
ModifiablePath property,
38+
MutablePath property,
3739
Map<String, Object> messageParameters,
3840
Map<String, Object> expressionVariables,
3941
Object dynamicPayload) {
4042
this.message = message;
4143
this.expressionLanguageFeatureLevel = expressionLanguageFeatureLevel;
4244
this.customViolation = customViolation;
43-
this.propertyPath = property;
45+
// at this point we make a copy of the path to avoid side effects
46+
this.propertyPath = property.materialize();
4447
this.messageParameters = toImmutableMap( messageParameters );
4548
this.expressionVariables = toImmutableMap( expressionVariables );
4649
this.dynamicPayload = dynamicPayload;
@@ -58,7 +61,7 @@ public boolean isCustomViolation() {
5861
return customViolation;
5962
}
6063

61-
public final ModifiablePath getPath() {
64+
public final Path getPath() {
6265
return propertyPath;
6366
}
6467

engine/src/main/java/org/hibernate/validator/internal/engine/constraintvalidation/CrossParameterConstraintValidatorContextImpl.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
import org.hibernate.validator.constraintvalidation.HibernateConstraintViolationBuilder;
1414
import org.hibernate.validator.constraintvalidation.HibernateCrossParameterConstraintValidatorContext;
15-
import org.hibernate.validator.internal.engine.path.ModifiablePath;
15+
import org.hibernate.validator.internal.engine.path.MutablePath;
1616
import org.hibernate.validator.internal.util.Contracts;
1717
import org.hibernate.validator.messageinterpolation.ExpressionLanguageFeatureLevel;
1818

@@ -25,7 +25,7 @@ public class CrossParameterConstraintValidatorContextImpl extends ConstraintVali
2525

2626
public CrossParameterConstraintValidatorContextImpl(List<String> methodParameterNames,
2727
ClockProvider clockProvider,
28-
ModifiablePath propertyPath,
28+
MutablePath propertyPath,
2929
ConstraintDescriptor<?> constraintDescriptor,
3030
Object constraintValidatorPayload,
3131
ExpressionLanguageFeatureLevel constraintExpressionLanguageFeatureLevel,
@@ -63,7 +63,7 @@ private class CrossParameterConstraintViolationBuilderImpl extends ConstraintVio
6363

6464
private final List<String> methodParameterNames;
6565

66-
private CrossParameterConstraintViolationBuilderImpl(List<String> methodParameterNames, String template, ModifiablePath path) {
66+
private CrossParameterConstraintViolationBuilderImpl(List<String> methodParameterNames, String template, MutablePath path) {
6767
super( template, path );
6868
this.methodParameterNames = methodParameterNames;
6969
}
@@ -77,7 +77,7 @@ public NodeBuilderDefinedContext addParameterNode(int index) {
7777
}
7878

7979
private void dropLeafNode() {
80-
propertyPath = ModifiablePath.createCopyWithoutLeafNode( propertyPath );
80+
propertyPath = MutablePath.createCopyWithoutLeafNode( propertyPath );
8181
}
8282
}
8383
}

0 commit comments

Comments
 (0)