6
6
*/
7
7
package org .hibernate .validator .internal .engine ;
8
8
9
- import static org .hibernate .validator .internal .util .CollectionHelper .newHashMap ;
10
9
import static org .hibernate .validator .internal .util .CollectionHelper .newHashSet ;
11
10
12
11
import java .lang .reflect .Executable ;
36
35
import org .hibernate .validator .internal .metadata .aggregated .BeanMetaData ;
37
36
import org .hibernate .validator .internal .metadata .core .MetaConstraint ;
38
37
import org .hibernate .validator .internal .util .ExecutableParameterNameProvider ;
39
- import org .hibernate .validator .internal .util .IdentitySet ;
40
38
import org .hibernate .validator .internal .util .logging .Log ;
41
39
import org .hibernate .validator .internal .util .logging .LoggerFactory ;
42
40
@@ -91,21 +89,15 @@ public class ValidationContext<T> {
91
89
private final Object executableReturnValue ;
92
90
93
91
/**
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}.
96
93
*/
97
- private final Map < Class <?>, IdentitySet > processedBeansPerGroup ;
94
+ private final Set < ProcessedUnit > processedUnits ;
98
95
99
96
/**
100
97
* Maps an object to a list of paths in which it has been validated. The objects are the bean instances.
101
98
*/
102
99
private final Map <Object , Set <PathImpl >> processedPathsPerBean ;
103
100
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
-
109
101
/**
110
102
* Contains all failing constraints so far.
111
103
*/
@@ -174,9 +166,8 @@ private ValidationContext(ConstraintValidatorManager constraintValidatorManager,
174
166
this .executableParameters = executableParameters ;
175
167
this .executableReturnValue = executableReturnValue ;
176
168
177
- this .processedBeansPerGroup = newHashMap ();
169
+ this .processedUnits = new HashSet <> ();
178
170
this .processedPathsPerBean = new IdentityHashMap <>();
179
- this .processedMetaConstraints = newHashMap ();
180
171
this .failingConstraintViolations = newHashSet ();
181
172
}
182
173
@@ -349,22 +340,11 @@ else if ( executableReturnValue != null ) {
349
340
}
350
341
351
342
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 ) );
355
344
}
356
345
357
346
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 ) );
368
348
}
369
349
370
350
public String getValidatedProperty () {
@@ -443,33 +423,17 @@ private boolean isSubPathOf(Path p1, Path p2) {
443
423
}
444
424
445
425
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 ) );
448
427
}
449
428
450
- private void markCurrentBeanAsProcessedForCurrentPath (Object value , PathImpl path ) {
429
+ private void markCurrentBeanAsProcessedForCurrentPath (Object bean , PathImpl path ) {
451
430
// 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 ) );
462
433
}
463
434
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 ) );
473
437
}
474
438
475
439
/**
@@ -609,15 +573,65 @@ public <T> ValidationContext<T> forValidateReturnValue(
609
573
}
610
574
}
611
575
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
+
613
626
private final Object bean ;
614
627
private final Path path ;
628
+ private final MetaConstraint <?> metaConstraint ;
615
629
private final int hashCode ;
616
630
617
- private BeanAndPath (Object bean , Path path ) {
631
+ private BeanPathMetaConstraintProcessedUnit (Object bean , Path path , MetaConstraint <?> metaConstraint ) {
618
632
this .bean = bean ;
619
633
this .path = path ;
620
- // pre-calculate hash code, the class is immutable and hashCode is needed often
634
+ this . metaConstraint = metaConstraint ;
621
635
this .hashCode = createHashCode ();
622
636
}
623
637
@@ -630,14 +644,17 @@ public boolean equals(Object o) {
630
644
return false ;
631
645
}
632
646
633
- BeanAndPath that = (BeanAndPath ) o ;
647
+ BeanPathMetaConstraintProcessedUnit that = (BeanPathMetaConstraintProcessedUnit ) o ;
634
648
635
649
if ( bean != that .bean ) { // instance equality
636
650
return false ;
637
651
}
638
652
if ( !path .equals ( that .path ) ) {
639
653
return false ;
640
654
}
655
+ if ( metaConstraint != that .metaConstraint ) {
656
+ return false ;
657
+ }
641
658
642
659
return true ;
643
660
}
@@ -650,6 +667,7 @@ public int hashCode() {
650
667
private int createHashCode () {
651
668
int result = System .identityHashCode ( bean );
652
669
result = 31 * result + path .hashCode ();
670
+ result = 31 * result + System .identityHashCode ( metaConstraint );
653
671
return result ;
654
672
}
655
673
}
0 commit comments