Skip to content

Commit 7c00b44

Browse files
gsmetgunnarmorling
authored andcommitted
HV-1480 Centralize the processed works in one single set
It avoids a lot of initialization/resizing and in the end it's more efficient.
1 parent ed8f3b5 commit 7c00b44

File tree

1 file changed

+69
-51
lines changed

1 file changed

+69
-51
lines changed

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

Lines changed: 69 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
*/
77
package org.hibernate.validator.internal.engine;
88

9-
import static org.hibernate.validator.internal.util.CollectionHelper.newHashMap;
109
import static org.hibernate.validator.internal.util.CollectionHelper.newHashSet;
1110

1211
import java.lang.reflect.Executable;
@@ -36,7 +35,6 @@
3635
import org.hibernate.validator.internal.metadata.aggregated.BeanMetaData;
3736
import org.hibernate.validator.internal.metadata.core.MetaConstraint;
3837
import org.hibernate.validator.internal.util.ExecutableParameterNameProvider;
39-
import org.hibernate.validator.internal.util.IdentitySet;
4038
import org.hibernate.validator.internal.util.logging.Log;
4139
import org.hibernate.validator.internal.util.logging.LoggerFactory;
4240

@@ -91,21 +89,15 @@ public class ValidationContext<T> {
9189
private final Object executableReturnValue;
9290

9391
/**
94-
* Maps a group to an identity set to keep track of already validated objects. We have to make sure
95-
* that each object gets only validated once per group and property path.
92+
* The set of already processed unit of works. See {@link ProcessedUnit}.
9693
*/
97-
private final Map<Class<?>, IdentitySet> processedBeansPerGroup;
94+
private final Set<ProcessedUnit> processedUnits;
9895

9996
/**
10097
* Maps an object to a list of paths in which it has been validated. The objects are the bean instances.
10198
*/
10299
private final Map<Object, Set<PathImpl>> processedPathsPerBean;
103100

104-
/**
105-
* Maps processed constraints to the bean and path for which they have been processed.
106-
*/
107-
private final Map<BeanAndPath, IdentitySet> processedMetaConstraints;
108-
109101
/**
110102
* Contains all failing constraints so far.
111103
*/
@@ -174,9 +166,8 @@ private ValidationContext(ConstraintValidatorManager constraintValidatorManager,
174166
this.executableParameters = executableParameters;
175167
this.executableReturnValue = executableReturnValue;
176168

177-
this.processedBeansPerGroup = newHashMap();
169+
this.processedUnits = new HashSet<>();
178170
this.processedPathsPerBean = new IdentityHashMap<>();
179-
this.processedMetaConstraints = newHashMap();
180171
this.failingConstraintViolations = newHashSet();
181172
}
182173

@@ -349,22 +340,11 @@ else if ( executableReturnValue != null ) {
349340
}
350341

351342
public boolean hasMetaConstraintBeenProcessed(Object bean, Path path, MetaConstraint<?> metaConstraint) {
352-
// TODO switch to proper multi key map (HF)
353-
IdentitySet processedConstraints = processedMetaConstraints.get( new BeanAndPath( bean, path ) );
354-
return processedConstraints != null && processedConstraints.contains( metaConstraint );
343+
return processedUnits.contains( new BeanPathMetaConstraintProcessedUnit( bean, path, metaConstraint ) );
355344
}
356345

357346
public void markConstraintProcessed(Object bean, Path path, MetaConstraint<?> metaConstraint) {
358-
// TODO switch to proper multi key map (HF)
359-
BeanAndPath beanAndPath = new BeanAndPath( bean, path );
360-
if ( processedMetaConstraints.containsKey( beanAndPath ) ) {
361-
processedMetaConstraints.get( beanAndPath ).add( metaConstraint );
362-
}
363-
else {
364-
IdentitySet set = new IdentitySet();
365-
set.add( metaConstraint );
366-
processedMetaConstraints.put( beanAndPath, set );
367-
}
347+
processedUnits.add( new BeanPathMetaConstraintProcessedUnit( bean, path, metaConstraint ) );
368348
}
369349

370350
public String getValidatedProperty() {
@@ -443,33 +423,17 @@ private boolean isSubPathOf(Path p1, Path p2) {
443423
}
444424

445425
private boolean isAlreadyValidatedForCurrentGroup(Object value, Class<?> group) {
446-
IdentitySet objectsProcessedInCurrentGroups = processedBeansPerGroup.get( group );
447-
return objectsProcessedInCurrentGroups != null && objectsProcessedInCurrentGroups.contains( value );
426+
return processedUnits.contains( new BeanGroupProcessedUnit( value, group ) );
448427
}
449428

450-
private void markCurrentBeanAsProcessedForCurrentPath(Object value, PathImpl path) {
429+
private void markCurrentBeanAsProcessedForCurrentPath(Object bean, PathImpl path) {
451430
// HV-1031 The path object is mutated as we traverse the object tree, hence copy it before saving it
452-
path = PathImpl.createCopy( path );
453-
454-
if ( processedPathsPerBean.containsKey( value ) ) {
455-
processedPathsPerBean.get( value ).add( path );
456-
}
457-
else {
458-
Set<PathImpl> set = new HashSet<>();
459-
set.add( path );
460-
processedPathsPerBean.put( value, set );
461-
}
431+
processedPathsPerBean.computeIfAbsent( bean, b -> new HashSet<>() )
432+
.add( PathImpl.createCopy( path ) );
462433
}
463434

464-
private void markCurrentBeanAsProcessedForCurrentGroup(Object value, Class<?> group) {
465-
if ( processedBeansPerGroup.containsKey( group ) ) {
466-
processedBeansPerGroup.get( group ).add( value );
467-
}
468-
else {
469-
IdentitySet set = new IdentitySet();
470-
set.add( value );
471-
processedBeansPerGroup.put( group, set );
472-
}
435+
private void markCurrentBeanAsProcessedForCurrentGroup(Object bean, Class<?> group) {
436+
processedUnits.add( new BeanGroupProcessedUnit( bean, group ) );
473437
}
474438

475439
/**
@@ -609,15 +573,65 @@ public <T> ValidationContext<T> forValidateReturnValue(
609573
}
610574
}
611575

612-
private static final class BeanAndPath {
576+
private interface ProcessedUnit {
577+
}
578+
579+
private static class BeanGroupProcessedUnit implements ProcessedUnit {
580+
581+
private final Object bean;
582+
private final Class<?> group;
583+
private final int hashCode;
584+
585+
private BeanGroupProcessedUnit(Object bean, Class<?> group) {
586+
this.bean = bean;
587+
this.group = group;
588+
this.hashCode = createHashCode();
589+
}
590+
591+
@Override
592+
public boolean equals(Object o) {
593+
if ( this == o ) {
594+
return true;
595+
}
596+
if ( o == null || getClass() != o.getClass() ) {
597+
return false;
598+
}
599+
600+
BeanGroupProcessedUnit that = (BeanGroupProcessedUnit) o;
601+
602+
if ( bean != that.bean ) { // instance equality
603+
return false;
604+
}
605+
if ( !group.equals( that.group ) ) {
606+
return false;
607+
}
608+
609+
return true;
610+
}
611+
612+
@Override
613+
public int hashCode() {
614+
return hashCode;
615+
}
616+
617+
private int createHashCode() {
618+
int result = System.identityHashCode( bean );
619+
result = 31 * result + group.hashCode();
620+
return result;
621+
}
622+
}
623+
624+
private static class BeanPathMetaConstraintProcessedUnit implements ProcessedUnit {
625+
613626
private final Object bean;
614627
private final Path path;
628+
private final MetaConstraint<?> metaConstraint;
615629
private final int hashCode;
616630

617-
private BeanAndPath(Object bean, Path path) {
631+
private BeanPathMetaConstraintProcessedUnit(Object bean, Path path, MetaConstraint<?> metaConstraint) {
618632
this.bean = bean;
619633
this.path = path;
620-
// pre-calculate hash code, the class is immutable and hashCode is needed often
634+
this.metaConstraint = metaConstraint;
621635
this.hashCode = createHashCode();
622636
}
623637

@@ -630,14 +644,17 @@ public boolean equals(Object o) {
630644
return false;
631645
}
632646

633-
BeanAndPath that = (BeanAndPath) o;
647+
BeanPathMetaConstraintProcessedUnit that = (BeanPathMetaConstraintProcessedUnit) o;
634648

635649
if ( bean != that.bean ) { // instance equality
636650
return false;
637651
}
638652
if ( !path.equals( that.path ) ) {
639653
return false;
640654
}
655+
if ( metaConstraint != that.metaConstraint ) {
656+
return false;
657+
}
641658

642659
return true;
643660
}
@@ -650,6 +667,7 @@ public int hashCode() {
650667
private int createHashCode() {
651668
int result = System.identityHashCode( bean );
652669
result = 31 * result + path.hashCode();
670+
result = 31 * result + System.identityHashCode( metaConstraint );
653671
return result;
654672
}
655673
}

0 commit comments

Comments
 (0)