|
7 | 7 | import java.lang.invoke.MethodHandles; |
8 | 8 | import java.util.Collections; |
9 | 9 | import java.util.HashSet; |
10 | | -import java.util.IdentityHashMap; |
11 | 10 | import java.util.Map; |
12 | 11 | import java.util.Set; |
13 | 12 |
|
@@ -103,18 +102,6 @@ abstract class AbstractValidationContext<T> implements BaseBeanValidationContext |
103 | 102 | @Lazy |
104 | 103 | private Set<BeanPathMetaConstraintProcessedUnit> processedPathUnits; |
105 | 104 |
|
106 | | - /** |
107 | | - * The set of already processed groups per bean ({@link BeanGroupProcessedUnit}). |
108 | | - */ |
109 | | - @Lazy |
110 | | - private Set<BeanGroupProcessedUnit> processedGroupUnits; |
111 | | - |
112 | | - /** |
113 | | - * Maps an object to a list of paths (represented by leaf nodes) in which it has been validated. The objects are the bean instances. |
114 | | - */ |
115 | | - @Lazy |
116 | | - private Map<Object, Set<NodeImpl>> processedPathsPerBean; |
117 | | - |
118 | 105 | /** |
119 | 106 | * Contains all failing constraints so far. |
120 | 107 | */ |
@@ -196,28 +183,19 @@ public ConstraintValidatorFactory getConstraintValidatorFactory() { |
196 | 183 | } |
197 | 184 |
|
198 | 185 | @Override |
199 | | - public boolean isBeanAlreadyValidated(Object value, Class<?> group, ModifiablePath path) { |
| 186 | + public boolean isBeanAlreadyValidated(Object value, Class<?> group, ValueContext<?, ?> valueContext) { |
200 | 187 | if ( !processedBeanTrackingEnabled ) { |
201 | 188 | return false; |
202 | 189 | } |
203 | | - |
204 | | - boolean alreadyValidated = isAlreadyValidatedForCurrentGroup( value, group ); |
205 | | - |
206 | | - if ( alreadyValidated ) { |
207 | | - alreadyValidated = isAlreadyValidatedForPath( value, path.getLeafNode() ); |
208 | | - } |
209 | | - |
210 | | - return alreadyValidated; |
| 190 | + return valueContext.isBeanAlreadyValidated( value, group ); |
211 | 191 | } |
212 | 192 |
|
213 | 193 | @Override |
214 | 194 | public void markCurrentBeanAsProcessed(ValueContext<?, ?> valueContext) { |
215 | 195 | if ( !processedBeanTrackingEnabled ) { |
216 | 196 | return; |
217 | 197 | } |
218 | | - |
219 | | - markCurrentBeanAsProcessedForCurrentGroup( valueContext.getCurrentBean(), valueContext.getCurrentGroup() ); |
220 | | - markCurrentBeanAsProcessedForCurrentPath( valueContext.getCurrentBean(), valueContext.getPropertyPath() ); |
| 198 | + valueContext.markCurrentGroupAsProcessed(); |
221 | 199 | } |
222 | 200 |
|
223 | 201 | @Override |
@@ -340,70 +318,13 @@ private String interpolate( |
340 | 318 | } |
341 | 319 | } |
342 | 320 |
|
343 | | - private boolean isAlreadyValidatedForPath(Object value, NodeImpl path) { |
344 | | - Set<NodeImpl> pathSet = getInitializedProcessedPathsPerBean().get( value ); |
345 | | - if ( pathSet == null ) { |
346 | | - return false; |
347 | | - } |
348 | | - |
349 | | - if ( path.isRootPath() ) { |
350 | | - return true; |
351 | | - } |
352 | | - |
353 | | - // Since this isAlreadyValidatedForPath(..) is only applicable for an object that is about to be cascaded into, |
354 | | - // it means that the new path we are testing cannot be a root path; also since we are cascading into inner |
355 | | - // objects, i.e. going further from the object tree root, it means that the new path cannot be shorter than |
356 | | - // the ones we've already encountered. |
357 | | - for ( NodeImpl p : pathSet ) { |
358 | | - if ( p.isSubPathOrContains( path ) ) { |
359 | | - return true; |
360 | | - } |
361 | | - } |
362 | | - return false; |
363 | | - } |
364 | | - |
365 | | - private boolean isAlreadyValidatedForCurrentGroup(Object value, Class<?> group) { |
366 | | - return getInitializedProcessedGroupUnits().contains( new BeanGroupProcessedUnit( value, group ) ); |
367 | | - } |
368 | | - |
369 | | - private void markCurrentBeanAsProcessedForCurrentPath(Object bean, ModifiablePath path) { |
370 | | - Map<Object, Set<NodeImpl>> processedPathsPerBean = getInitializedProcessedPathsPerBean(); |
371 | | - |
372 | | - Set<NodeImpl> processedPaths = processedPathsPerBean.get( bean ); |
373 | | - if ( processedPaths == null ) { |
374 | | - processedPaths = new HashSet<>(); |
375 | | - processedPathsPerBean.put( bean, processedPaths ); |
376 | | - } |
377 | | - |
378 | | - // HV-1031 The path object is mutated as we traverse the object tree, hence we use the node which is not (for the most part): |
379 | | - processedPaths.add( path.getLeafNode() ); |
380 | | - } |
381 | | - |
382 | | - private void markCurrentBeanAsProcessedForCurrentGroup(Object bean, Class<?> group) { |
383 | | - getInitializedProcessedGroupUnits().add( new BeanGroupProcessedUnit( bean, group ) ); |
384 | | - } |
385 | | - |
386 | 321 | private Set<BeanPathMetaConstraintProcessedUnit> getInitializedProcessedPathUnits() { |
387 | 322 | if ( processedPathUnits == null ) { |
388 | 323 | processedPathUnits = new HashSet<>(); |
389 | 324 | } |
390 | 325 | return processedPathUnits; |
391 | 326 | } |
392 | 327 |
|
393 | | - private Set<BeanGroupProcessedUnit> getInitializedProcessedGroupUnits() { |
394 | | - if ( processedGroupUnits == null ) { |
395 | | - processedGroupUnits = new HashSet<>(); |
396 | | - } |
397 | | - return processedGroupUnits; |
398 | | - } |
399 | | - |
400 | | - private Map<Object, Set<NodeImpl>> getInitializedProcessedPathsPerBean() { |
401 | | - if ( processedPathsPerBean == null ) { |
402 | | - processedPathsPerBean = new IdentityHashMap<>(); |
403 | | - } |
404 | | - return processedPathsPerBean; |
405 | | - } |
406 | | - |
407 | 328 | private Set<ConstraintViolation<T>> getInitializedFailingConstraintViolations() { |
408 | 329 | if ( failingConstraintViolations == null ) { |
409 | 330 | failingConstraintViolations = new HashSet<>(); |
@@ -462,48 +383,4 @@ private int createHashCode() { |
462 | 383 | } |
463 | 384 | } |
464 | 385 |
|
465 | | - private static final class BeanGroupProcessedUnit { |
466 | | - |
467 | | - // these fields are final but we don't mark them as final as an optimization |
468 | | - private Object bean; |
469 | | - private Class<?> group; |
470 | | - private int hashCode; |
471 | | - |
472 | | - BeanGroupProcessedUnit(Object bean, Class<?> group) { |
473 | | - this.bean = bean; |
474 | | - this.group = group; |
475 | | - this.hashCode = createHashCode(); |
476 | | - } |
477 | | - |
478 | | - @Override |
479 | | - public boolean equals(Object o) { |
480 | | - // null check intentionally left out |
481 | | - if ( this == o ) { |
482 | | - return true; |
483 | | - } |
484 | | - |
485 | | - // No need to check if the class matches because of how this class is used in the set. |
486 | | - BeanGroupProcessedUnit that = (BeanGroupProcessedUnit) o; |
487 | | - |
488 | | - if ( bean != that.bean ) { // instance equality |
489 | | - return false; |
490 | | - } |
491 | | - if ( !group.equals( that.group ) ) { |
492 | | - return false; |
493 | | - } |
494 | | - |
495 | | - return true; |
496 | | - } |
497 | | - |
498 | | - @Override |
499 | | - public int hashCode() { |
500 | | - return hashCode; |
501 | | - } |
502 | | - |
503 | | - private int createHashCode() { |
504 | | - int result = System.identityHashCode( bean ); |
505 | | - result = 31 * result + group.hashCode(); |
506 | | - return result; |
507 | | - } |
508 | | - } |
509 | 386 | } |
0 commit comments