Skip to content

Commit 379e5a9

Browse files
committed
HV-2135 Leverage the path/node mutability
1 parent fac185a commit 379e5a9

12 files changed

+157
-27
lines changed

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

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,9 @@ private <U> boolean validateConstraintsForSingleDefaultGroupElement(BaseBeanVali
528528

529529
valueContext.setCurrentGroup( defaultSequenceMember.getDefiningClass() );
530530

531+
BeanValueContext.ValueState<Object> originalValueState = valueContext.getCurrentValueState();
532+
valueContext.appendEmptyNode();
533+
531534
for ( MetaConstraint<?> metaConstraint : metaConstraints ) {
532535
// HV-466, an interface implemented more than one time in the hierarchy has to be validated only one
533536
// time. An interface can define more than one constraint, we have to check the class we are validating.
@@ -547,6 +550,10 @@ private <U> boolean validateConstraintsForSingleDefaultGroupElement(BaseBeanVali
547550

548551
validationSuccessful = validationSuccessful && tmp;
549552
}
553+
554+
// reset the value context to the state before this call
555+
valueContext.resetValueState( originalValueState );
556+
550557
return validationSuccessful;
551558
}
552559

@@ -566,18 +573,24 @@ private void validateConstraintsForNonDefaultGroup(BaseBeanValidationContext<?>
566573
private boolean validateMetaConstraints(BaseBeanValidationContext<?> validationContext, ValueContext<?, Object> valueContext, Object parent,
567574
Iterable<MetaConstraint<?>> constraints) {
568575
boolean validationSuccessful = true;
576+
BeanValueContext.ValueState<Object> originalValueState = valueContext.getCurrentValueState();
577+
valueContext.appendEmptyNode();
578+
569579
for ( MetaConstraint<?> metaConstraint : constraints ) {
570580
validationSuccessful = validateMetaConstraint( validationContext, valueContext, parent, metaConstraint ) && validationSuccessful;
571581
if ( shouldFailFast( validationContext ) ) {
572582
break;
573583
}
574584
}
585+
586+
// reset the value context to the state before this call
587+
valueContext.resetValueState( originalValueState );
588+
575589
return validationSuccessful;
576590
}
577591

578592
private boolean validateMetaConstraint(BaseBeanValidationContext<?> validationContext, ValueContext<?, Object> valueContext, Object parent, MetaConstraint<?> metaConstraint) {
579-
BeanValueContext.ValueState<Object> originalValueState = valueContext.getCurrentValueState();
580-
valueContext.appendNode( metaConstraint.getLocation() );
593+
valueContext.updateNode( metaConstraint.getLocation() );
581594
boolean success = true;
582595

583596
if ( isValidationRequired( validationContext, valueContext, metaConstraint ) ) {
@@ -591,9 +604,6 @@ private boolean validateMetaConstraint(BaseBeanValidationContext<?> validationCo
591604
validationContext.markConstraintProcessed( valueContext, metaConstraint );
592605
}
593606

594-
// reset the value context to the state before this call
595-
valueContext.resetValueState( originalValueState );
596-
597607
return success;
598608
}
599609

@@ -691,11 +701,31 @@ private class CascadingValueReceiver implements ValueExtractor.ValueReceiver {
691701
private final BaseBeanValidationContext<?> validationContext;
692702
private final ValueContext<?, ?> valueContext;
693703
private final ContainerCascadingMetaData cascadingMetaData;
704+
private final BeanValueContext<?, Object> cascadedValueContext;
694705

695706
public CascadingValueReceiver(BaseBeanValidationContext<?> validationContext, ValueContext<?, ?> valueContext, ContainerCascadingMetaData cascadingMetaData) {
696707
this.validationContext = validationContext;
697708
this.valueContext = valueContext;
698709
this.cascadingMetaData = cascadingMetaData;
710+
this.cascadedValueContext = ValueContexts.getLocalExecutionContextForBean(
711+
valueContext,
712+
validatorScopedContext.getParameterNameProvider(),
713+
null,
714+
null,
715+
valueContext.getPropertyPath()
716+
);
717+
}
718+
719+
private BeanValueContext<?, Object> resetCascadedValueContext(Object value) {
720+
Contracts.assertNotNull( value, "value cannot be null" );
721+
722+
BeanMetaData<?> currentBeanMetaData = cascadedValueContext.getCurrentBeanMetaData();
723+
if ( currentBeanMetaData == null || currentBeanMetaData.getBeanClass() != value.getClass() ) {
724+
currentBeanMetaData = beanMetaDataManager.getBeanMetaData( value.getClass() );
725+
}
726+
cascadedValueContext.reset( value, valueContext.getPropertyPath(), currentBeanMetaData );
727+
cascadedValueContext.setCurrentValidatedValue( value );
728+
return cascadedValueContext;
699729
}
700730

701731
@Override
@@ -738,7 +768,7 @@ private void doValidate(Object value, String nodeName) {
738768
// already and need only to pass the current element
739769
ValidationOrder validationOrder = validationOrderGenerator.getValidationOrder( currentGroup, currentGroup != originalGroup );
740770

741-
BeanValueContext<?, Object> cascadedValueContext = buildNewLocalExecutionContext( valueContext, value );
771+
BeanValueContext<?, Object> cascadedValueContext = resetCascadedValueContext( value );
742772

743773
if ( cascadingMetaData.getDeclaredContainerClass() != null ) {
744774
cascadedValueContext.setTypeParameter( cascadingMetaData.getDeclaredContainerClass(), cascadingMetaData.getDeclaredTypeParameterIndex() );

engine/src/main/java/org/hibernate/validator/internal/engine/path/MutableNode.java

Lines changed: 55 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ public class MutableNode
4949

5050
static {
5151
ROOT_NODE = MutableNode.createBeanNode( null );
52-
ROOT_NODE.valueSet = true;
5352
ROOT_NODE.nodes = new MutableNode[] { ROOT_NODE };
5453
ROOT_NODE.hashCode();
5554
}
@@ -66,19 +65,18 @@ public class MutableNode
6665
public static final String MAP_KEY_NODE_NAME = "<map key>";
6766
public static final String MAP_VALUE_NODE_NAME = "<map value>";
6867

69-
private final String name;
7068
private final MutableNode parent;
71-
private final ElementKind kind;
7269
private final int size;
70+
private String name;
71+
private ElementKind kind;
7372
private boolean isIterable;
7473
private Integer index;
7574
private Object key;
7675

7776
//type-specific attributes
7877
private final Class<?>[] parameterTypes;
79-
private final Integer parameterIndex;
78+
private Integer parameterIndex;
8079
private Object value;
81-
private boolean valueSet;
8280
private Class<?> containerClass;
8381
private Integer typeArgumentIndex;
8482

@@ -88,15 +86,14 @@ public class MutableNode
8886

8987
private MutableNode(
9088
String name, MutableNode parent, boolean isIterable, Integer index, Object key, ElementKind kind, Class<?>[] parameterTypes,
91-
Integer parameterIndex, Object value, boolean valueSet, Class<?> containerClass, Integer typeArgumentIndex
89+
Integer parameterIndex, Object value, Class<?> containerClass, Integer typeArgumentIndex
9290
) {
9391
this.name = name;
9492
this.parent = parent;
9593
this.size = ( parent == null ? 0 : parent.size ) + 1;
9694
this.index = index;
9795
this.key = key;
9896
this.value = value;
99-
this.valueSet = valueSet;
10097
this.isIterable = isIterable;
10198
this.kind = kind;
10299
this.parameterTypes = parameterTypes;
@@ -105,6 +102,22 @@ private MutableNode(
105102
this.typeArgumentIndex = typeArgumentIndex;
106103
}
107104

105+
public static MutableNode createNode(MutableNode parent) {
106+
return new MutableNode(
107+
null,
108+
parent,
109+
false,
110+
null,
111+
null,
112+
null,
113+
EMPTY_CLASS_ARRAY,
114+
null,
115+
null,
116+
null,
117+
null
118+
);
119+
}
120+
108121
//TODO It would be nicer if we could return PropertyNode
109122
public static MutableNode createPropertyNode(String name, MutableNode parent) {
110123
return new MutableNode(
@@ -117,7 +130,6 @@ public static MutableNode createPropertyNode(String name, MutableNode parent) {
117130
EMPTY_CLASS_ARRAY,
118131
null,
119132
null,
120-
false,
121133
null,
122134
null
123135
);
@@ -134,7 +146,6 @@ public static MutableNode createContainerElementNode(String name, MutableNode pa
134146
EMPTY_CLASS_ARRAY,
135147
null,
136148
null,
137-
false,
138149
null,
139150
null
140151
);
@@ -151,7 +162,6 @@ public static MutableNode createParameterNode(String name, MutableNode parent, i
151162
EMPTY_CLASS_ARRAY,
152163
parameterIndex,
153164
null,
154-
false,
155165
null,
156166
null
157167
);
@@ -168,18 +178,17 @@ public static MutableNode createCrossParameterNode(MutableNode parent) {
168178
EMPTY_CLASS_ARRAY,
169179
null,
170180
null,
171-
false,
172181
null,
173182
null
174183
);
175184
}
176185

177186
public static MutableNode createMethodNode(String name, MutableNode parent, Class<?>[] parameterTypes) {
178-
return new MutableNode( name, parent, false, null, null, ElementKind.METHOD, parameterTypes, null, null, false, null, null );
187+
return new MutableNode( name, parent, false, null, null, ElementKind.METHOD, parameterTypes, null, null, null, null );
179188
}
180189

181190
public static MutableNode createConstructorNode(String name, MutableNode parent, Class<?>[] parameterTypes) {
182-
return new MutableNode( name, parent, false, null, null, ElementKind.CONSTRUCTOR, parameterTypes, null, null, false, null, null );
191+
return new MutableNode( name, parent, false, null, null, ElementKind.CONSTRUCTOR, parameterTypes, null, null, null, null );
183192
}
184193

185194
public static MutableNode createBeanNode(MutableNode parent) {
@@ -193,7 +202,6 @@ public static MutableNode createBeanNode(MutableNode parent) {
193202
EMPTY_CLASS_ARRAY,
194203
null,
195204
null,
196-
false,
197205
null,
198206
null
199207
);
@@ -210,7 +218,6 @@ public static MutableNode createReturnValue(MutableNode parent) {
210218
EMPTY_CLASS_ARRAY,
211219
null,
212220
null,
213-
false,
214221
null,
215222
null
216223
);
@@ -246,9 +253,11 @@ public void setTypeParameter(Class<?> containerClass, Integer typeArgumentIndex)
246253
public void reset() {
247254
isIterable = false;
248255
index = null;
256+
parameterIndex = null;
249257
key = null;
250258
typeArgumentIndex = null;
251259
containerClass = null;
260+
value = null;
252261
}
253262

254263
@Override
@@ -628,6 +637,37 @@ public boolean isSubPathOrContains(MutableNode other) {
628637
return curr.isRootPath() && otherCurr.isRootPath();
629638
}
630639

640+
public void resetAsProperty(String resolvedPropertyName) {
641+
reset();
642+
this.name = resolvedPropertyName;
643+
this.kind = ElementKind.PROPERTY;
644+
}
645+
646+
public void resetAsBeanNode() {
647+
reset();
648+
this.kind = ElementKind.BEAN;
649+
this.name = null;
650+
}
651+
652+
public void resetAsParameter(String parameterName, int index) {
653+
reset();
654+
this.kind = ElementKind.PARAMETER;
655+
this.name = parameterName;
656+
this.parameterIndex = index;
657+
}
658+
659+
public void resetAsReturnValue() {
660+
reset();
661+
this.name = RETURN_VALUE_NODE_NAME;
662+
this.kind = ElementKind.RETURN_VALUE;
663+
}
664+
665+
public void resetAsCrossParameter() {
666+
reset();
667+
this.name = CROSS_PARAMETER_NODE_NAME;
668+
this.kind = ElementKind.CROSS_PARAMETER;
669+
}
670+
631671
protected static class NodeIterator implements Iterator<Path.Node> {
632672
private final MutableNode[] array;
633673
private int index;

engine/src/main/java/org/hibernate/validator/internal/engine/path/MutablePath.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,11 @@ private void addMethodNode(String name, Class<?>[] parameterTypes) {
151151
currentLeafNode = MutableNode.createMethodNode( name, parent, parameterTypes );
152152
}
153153

154+
public void addEmptyNode() {
155+
MutableNode parent = currentLeafNode;
156+
currentLeafNode = MutableNode.createNode( parent );
157+
}
158+
154159
public void makeLeafNodeIterable() {
155160
currentLeafNode.makeIterable();
156161
}

engine/src/main/java/org/hibernate/validator/internal/engine/valuecontext/BeanValueContext.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public final class BeanValueContext<T, V> extends ValueContext<T, V> {
2323
/**
2424
* The metadata of the current bean.
2525
*/
26-
private final BeanMetaData<T> currentBeanMetaData;
26+
private BeanMetaData<?> currentBeanMetaData;
2727

2828
/**
2929
* When we check whether the bean was validated we need to check that it was validated for the requested group.
@@ -43,8 +43,20 @@ public final class BeanValueContext<T, V> extends ValueContext<T, V> {
4343
this.currentBeanMetaData = currentBeanMetaData;
4444
}
4545

46+
@SuppressWarnings("unchecked")
4647
public BeanMetaData<T> getCurrentBeanMetaData() {
47-
return currentBeanMetaData;
48+
return (BeanMetaData<T>) currentBeanMetaData;
49+
}
50+
51+
public void reset(Object currentBean, MutablePath propertyPath, BeanMetaData<?> currentBeanMetaData) {
52+
this.currentBeanMetaData = currentBeanMetaData;
53+
this.currentValidatable = currentBeanMetaData;
54+
this.currentBean = currentBean;
55+
this.propertyPath = propertyPath;
56+
this.alreadyProcessedGroups = null;
57+
this.alreadyProcessedMetaConstraints = null;
58+
this.currentGroup = null;
59+
this.previousGroup = null;
4860
}
4961

5062
@Override

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

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,12 @@ public abstract sealed class ValueContext<T, V> permits BeanValueContext, Execut
3535
/**
3636
* The current bean which gets validated. This is the bean hosting the constraints which get validated.
3737
*/
38-
protected final T currentBean;
38+
protected Object currentBean;
3939

4040
/**
4141
* The current property path we are validating.
4242
*/
43-
private MutablePath propertyPath;
43+
protected MutablePath propertyPath;
4444

4545
/**
4646
* The current group we are validating.
@@ -57,7 +57,7 @@ public abstract sealed class ValueContext<T, V> permits BeanValueContext, Execut
5757
*/
5858
private V currentValue;
5959

60-
private final Validatable currentValidatable;
60+
protected Validatable currentValidatable;
6161

6262
/**
6363
* The {@code ConstraintLocationKind} the constraint was defined on
@@ -80,8 +80,9 @@ public final Class<?> getCurrentGroup() {
8080
return currentGroup;
8181
}
8282

83+
@SuppressWarnings("unchecked")
8384
public final T getCurrentBean() {
84-
return currentBean;
85+
return (T) currentBean;
8586
}
8687

8788
public Validatable getCurrentValidatable() {
@@ -115,6 +116,16 @@ public final void appendTypeParameterNode(String nodeName) {
115116
}
116117
}
117118

119+
public void appendEmptyNode() {
120+
MutablePath newPath = MutablePath.createCopy( propertyPath );
121+
newPath.addEmptyNode();
122+
propertyPath = newPath;
123+
}
124+
125+
public final void updateNode(ConstraintLocation location) {
126+
location.applyTo( parameterNameProvider, propertyPath );
127+
}
128+
118129
public final void markCurrentPropertyAsIterable() {
119130
propertyPath.makeLeafNodeIterable();
120131
}

engine/src/main/java/org/hibernate/validator/internal/metadata/location/AbstractPropertyConstraintLocation.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ public void appendTo(ExecutableParameterNameProvider parameterNameProvider, Muta
5555
path.addPropertyNode( property.getResolvedPropertyName() );
5656
}
5757

58+
@Override
59+
public void applyTo(ExecutableParameterNameProvider parameterNameProvider, MutablePath path) {
60+
path.getLeafNode().resetAsProperty( property.getResolvedPropertyName() );
61+
}
62+
5863
@Override
5964
public Object getValue(Object parent) {
6065
return propertyAccessor.getValueFrom( parent );

engine/src/main/java/org/hibernate/validator/internal/metadata/location/BeanConstraintLocation.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,11 @@ public void appendTo(ExecutableParameterNameProvider parameterNameProvider, Muta
5858
path.addBeanNode();
5959
}
6060

61+
@Override
62+
public void applyTo(ExecutableParameterNameProvider parameterNameProvider, MutablePath path) {
63+
path.getLeafNode().resetAsBeanNode();
64+
}
65+
6166
@Override
6267
public Object getValue(Object parent) {
6368
return parent;

0 commit comments

Comments
 (0)