Skip to content

Commit 74fa66a

Browse files
committed
HV-1831 Move metaconstraint-per-bean tracking to value context
Signed-off-by: marko-bekhta <[email protected]>
1 parent e343f17 commit 74fa66a

File tree

6 files changed

+46
-75
lines changed

6 files changed

+46
-75
lines changed

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -588,7 +588,7 @@ private boolean validateMetaConstraint(BaseBeanValidationContext<?> validationCo
588588

589589
success = metaConstraint.validateConstraint( validationContext, valueContext );
590590

591-
validationContext.markConstraintProcessed( valueContext.getCurrentBean(), valueContext.getPropertyPath(), metaConstraint );
591+
validationContext.markConstraintProcessed( valueContext, metaConstraint );
592592
}
593593

594594
// reset the value context to the state before this call
@@ -1313,8 +1313,7 @@ private boolean isValidationRequired(BaseBeanValidationContext<?> validationCont
13131313
return false;
13141314
}
13151315
if ( validationContext.hasMetaConstraintBeenProcessed(
1316-
valueContext.getCurrentBean(),
1317-
valueContext.getPropertyPath(),
1316+
valueContext,
13181317
metaConstraint
13191318
) ) {
13201319
return false;

engine/src/main/java/org/hibernate/validator/internal/engine/validationcontext/AbstractValidationContext.java

Lines changed: 4 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorManager;
2525
import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintViolationCreationContext;
2626
import org.hibernate.validator.internal.engine.path.ModifiablePath;
27-
import org.hibernate.validator.internal.engine.path.NodeImpl;
2827
import org.hibernate.validator.internal.engine.valuecontext.ValueContext;
2928
import org.hibernate.validator.internal.metadata.aggregated.BeanMetaData;
3029
import org.hibernate.validator.internal.metadata.core.MetaConstraint;
@@ -96,12 +95,6 @@ abstract class AbstractValidationContext<T> implements BaseBeanValidationContext
9695
*/
9796
private final boolean processedBeanTrackingEnabled;
9897

99-
/**
100-
* The set of already processed meta constraints per bean - path ({@link BeanPathMetaConstraintProcessedUnit}).
101-
*/
102-
@Lazy
103-
private Set<BeanPathMetaConstraintProcessedUnit> processedPathUnits;
104-
10598
/**
10699
* Contains all failing constraints so far.
107100
*/
@@ -248,25 +241,25 @@ protected abstract ConstraintViolation<T> createConstraintViolation(
248241
ConstraintViolationCreationContext constraintViolationCreationContext);
249242

250243
@Override
251-
public boolean hasMetaConstraintBeenProcessed(Object bean, ModifiablePath path, MetaConstraint<?> metaConstraint) {
244+
public boolean hasMetaConstraintBeenProcessed(ValueContext<?, ?> valueContext, MetaConstraint<?> metaConstraint) {
252245
// this is only useful if the constraint is defined for more than 1 group as in the case it's only
253246
// defined for one group, there is no chance it's going to be called twice.
254247
if ( metaConstraint.isDefinedForOneGroupOnly() ) {
255248
return false;
256249
}
257250

258-
return getInitializedProcessedPathUnits().contains( new BeanPathMetaConstraintProcessedUnit( bean, path, metaConstraint ) );
251+
return valueContext.hasMetaConstraintBeenProcessed( metaConstraint );
259252
}
260253

261254
@Override
262-
public void markConstraintProcessed(Object bean, ModifiablePath path, MetaConstraint<?> metaConstraint) {
255+
public void markConstraintProcessed(ValueContext<?, ?> valueContext, MetaConstraint<?> metaConstraint) {
263256
// this is only useful if the constraint is defined for more than 1 group as in the case it's only
264257
// defined for one group, there is no chance it's going to be called twice.
265258
if ( metaConstraint.isDefinedForOneGroupOnly() ) {
266259
return;
267260
}
268261

269-
getInitializedProcessedPathUnits().add( new BeanPathMetaConstraintProcessedUnit( bean, path, metaConstraint ) );
262+
valueContext.markConstraintProcessed( metaConstraint );
270263
}
271264

272265
@Override
@@ -318,69 +311,11 @@ private String interpolate(
318311
}
319312
}
320313

321-
private Set<BeanPathMetaConstraintProcessedUnit> getInitializedProcessedPathUnits() {
322-
if ( processedPathUnits == null ) {
323-
processedPathUnits = new HashSet<>();
324-
}
325-
return processedPathUnits;
326-
}
327-
328314
private Set<ConstraintViolation<T>> getInitializedFailingConstraintViolations() {
329315
if ( failingConstraintViolations == null ) {
330316
failingConstraintViolations = new HashSet<>();
331317
}
332318
return failingConstraintViolations;
333319
}
334320

335-
private static final class BeanPathMetaConstraintProcessedUnit {
336-
337-
// these fields are final but we don't mark them as final as an optimization
338-
private Object bean;
339-
private NodeImpl pathLeaf;
340-
private MetaConstraint<?> metaConstraint;
341-
private int hashCode;
342-
343-
BeanPathMetaConstraintProcessedUnit(Object bean, ModifiablePath path, MetaConstraint<?> metaConstraint) {
344-
this.bean = bean;
345-
this.pathLeaf = path.getLeafNode(); // because the leaf represent the entire path.
346-
this.metaConstraint = metaConstraint;
347-
this.hashCode = createHashCode();
348-
}
349-
350-
@Override
351-
public boolean equals(Object o) {
352-
// null check intentionally left out
353-
if ( this == o ) {
354-
return true;
355-
}
356-
357-
// No need to check if the class matches because of how this class is used in the set.
358-
BeanPathMetaConstraintProcessedUnit that = (BeanPathMetaConstraintProcessedUnit) o;
359-
360-
if ( bean != that.bean ) { // instance equality
361-
return false;
362-
}
363-
if ( metaConstraint != that.metaConstraint ) {
364-
return false;
365-
}
366-
if ( !pathLeaf.equals( that.pathLeaf ) ) {
367-
return false;
368-
}
369-
370-
return true;
371-
}
372-
373-
@Override
374-
public int hashCode() {
375-
return hashCode;
376-
}
377-
378-
private int createHashCode() {
379-
int result = System.identityHashCode( bean );
380-
result = 31 * result + pathLeaf.hashCode();
381-
result = 31 * result + System.identityHashCode( metaConstraint );
382-
return result;
383-
}
384-
}
385-
386321
}

engine/src/main/java/org/hibernate/validator/internal/engine/validationcontext/BaseBeanValidationContext.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import jakarta.validation.Validator;
99

1010
import org.hibernate.validator.internal.engine.ValidatorImpl;
11-
import org.hibernate.validator.internal.engine.path.ModifiablePath;
1211
import org.hibernate.validator.internal.engine.valuecontext.ValueContext;
1312
import org.hibernate.validator.internal.metadata.aggregated.BeanMetaData;
1413
import org.hibernate.validator.internal.metadata.core.MetaConstraint;
@@ -38,9 +37,9 @@ public interface BaseBeanValidationContext<T> extends ValidationContext<T> {
3837

3938
void markCurrentBeanAsProcessed(ValueContext<?, ?> valueContext);
4039

41-
boolean hasMetaConstraintBeenProcessed(Object bean, ModifiablePath path, MetaConstraint<?> metaConstraint);
40+
boolean hasMetaConstraintBeenProcessed(ValueContext<?, ?> valueContext, MetaConstraint<?> metaConstraint);
4241

43-
void markConstraintProcessed(Object bean, ModifiablePath path, MetaConstraint<?> metaConstraint);
42+
void markConstraintProcessed(ValueContext<?, ?> valueContext, MetaConstraint<?> metaConstraint);
4443

4544
/**
4645
* @return {@code true} if current validation context can and should process passed meta constraint. Is used in

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,13 @@
55
package org.hibernate.validator.internal.engine.valuecontext;
66

77
import java.util.HashSet;
8+
import java.util.IdentityHashMap;
9+
import java.util.Map;
810
import java.util.Set;
911

1012
import org.hibernate.validator.internal.engine.path.ModifiablePath;
1113
import org.hibernate.validator.internal.metadata.aggregated.BeanMetaData;
14+
import org.hibernate.validator.internal.metadata.core.MetaConstraint;
1215
import org.hibernate.validator.internal.util.ExecutableParameterNameProvider;
1316
import org.hibernate.validator.internal.util.stereotypes.Lazy;
1417

@@ -29,6 +32,12 @@ public final class BeanValueContext<T, V> extends ValueContext<T, V> {
2932
@Lazy
3033
private Set<Class<?>> alreadyProcessedGroups;
3134

35+
/**
36+
* To track when the constraint is in multiple groups, and it was already processed for some other group.
37+
*/
38+
@Lazy
39+
private Map<MetaConstraint<?>, Boolean> alreadyProcessedMetaConstraints;
40+
3241
BeanValueContext(ValueContext<?, ?> parentContext, ExecutableParameterNameProvider parameterNameProvider, T currentBean, BeanMetaData<T> currentBeanMetaData, ModifiablePath propertyPath) {
3342
super( parentContext, parameterNameProvider, currentBean, currentBeanMetaData, propertyPath );
3443
this.currentBeanMetaData = currentBeanMetaData;
@@ -67,4 +76,17 @@ public void markCurrentGroupAsProcessed() {
6776
protected boolean isProcessedForGroup(Class<?> group) {
6877
return group == this.currentGroup || ( this.alreadyProcessedGroups != null && alreadyProcessedGroups.contains( group ) );
6978
}
79+
80+
@Override
81+
public void markConstraintProcessed(MetaConstraint<?> metaConstraint) {
82+
if ( alreadyProcessedMetaConstraints == null ) {
83+
alreadyProcessedMetaConstraints = new IdentityHashMap<>();
84+
}
85+
alreadyProcessedMetaConstraints.put( metaConstraint, Boolean.TRUE );
86+
}
87+
88+
@Override
89+
public boolean hasMetaConstraintBeenProcessed(MetaConstraint<?> metaConstraint) {
90+
return alreadyProcessedMetaConstraints != null && alreadyProcessedMetaConstraints.containsKey( metaConstraint );
91+
}
7092
}

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
package org.hibernate.validator.internal.engine.valuecontext;
66

77
import org.hibernate.validator.internal.engine.path.ModifiablePath;
8+
import org.hibernate.validator.internal.metadata.core.MetaConstraint;
89
import org.hibernate.validator.internal.metadata.facets.Validatable;
910
import org.hibernate.validator.internal.util.ExecutableParameterNameProvider;
1011

@@ -33,4 +34,14 @@ public void markCurrentGroupAsProcessed() {
3334
protected boolean isProcessedForGroup(Class<?> group) {
3435
return false;
3536
}
37+
38+
@Override
39+
public void markConstraintProcessed(MetaConstraint<?> metaConstraint) {
40+
// do nothing as usual
41+
}
42+
43+
@Override
44+
public boolean hasMetaConstraintBeenProcessed(MetaConstraint<?> metaConstraint) {
45+
return false;
46+
}
3647
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import org.hibernate.validator.internal.engine.path.ModifiablePath;
1111
import org.hibernate.validator.internal.engine.valueextraction.AnnotatedObject;
1212
import org.hibernate.validator.internal.engine.valueextraction.ArrayElement;
13+
import org.hibernate.validator.internal.metadata.core.MetaConstraint;
1314
import org.hibernate.validator.internal.metadata.facets.Cascadable;
1415
import org.hibernate.validator.internal.metadata.facets.Validatable;
1516
import org.hibernate.validator.internal.metadata.location.ConstraintLocation;
@@ -154,6 +155,10 @@ public final void setCurrentGroup(Class<?> currentGroup) {
154155

155156
protected abstract boolean isProcessedForGroup(Class<?> group);
156157

158+
public abstract void markConstraintProcessed(MetaConstraint<?> metaConstraint);
159+
160+
public abstract boolean hasMetaConstraintBeenProcessed(MetaConstraint<?> metaConstraint);
161+
157162
public final void setCurrentValidatedValue(V currentValue) {
158163
propertyPath.setLeafNodeValueIfRequired( currentValue );
159164
this.currentValue = currentValue;

0 commit comments

Comments
 (0)