66 */
77package org .hibernate .validator .internal .engine .validationcontext ;
88
9- import static org .hibernate .validator .internal .util .CollectionHelper .newHashSet ;
10-
119import java .lang .invoke .MethodHandles ;
10+ import java .util .Collections ;
1211import java .util .HashSet ;
1312import java .util .IdentityHashMap ;
1413import java .util .Iterator ;
3534import org .hibernate .validator .internal .metadata .descriptor .ConstraintDescriptorImpl ;
3635import org .hibernate .validator .internal .util .logging .Log ;
3736import org .hibernate .validator .internal .util .logging .LoggerFactory ;
37+ import org .hibernate .validator .internal .util .stereotypes .Lazy ;
3838
3939/**
4040 * Context object keeping track of all required data for a validation call.
@@ -73,49 +73,53 @@ abstract class AbstractValidationContext<T> implements BaseBeanValidationContext
7373 private final BeanMetaData <T > rootBeanMetaData ;
7474
7575 /**
76- * The set of already processed meta constraints per bean - path ({@link BeanPathMetaConstraintProcessedUnit}) .
76+ * The constraint factory which should be used in this context .
7777 */
78- private final Set < BeanPathMetaConstraintProcessedUnit > processedPathUnits ;
78+ private final ConstraintValidatorFactory constraintValidatorFactory ;
7979
8080 /**
81- * The set of already processed groups per bean ({@link BeanGroupProcessedUnit}) .
81+ * Context containing all {@link Validator} level helpers and configuration properties .
8282 */
83- private final Set < BeanGroupProcessedUnit > processedGroupUnits ;
83+ protected final ValidatorScopedContext validatorScopedContext ;
8484
8585 /**
86- * Maps an object to a list of paths in which it has been validated. The objects are the bean instances .
86+ * Allows a JPA provider to decide whether a property should be validated .
8787 */
88- private final Map < Object , Set < PathImpl >> processedPathsPerBean ;
88+ private final TraversableResolver traversableResolver ;
8989
9090 /**
91- * Contains all failing constraints so far .
91+ * The constraint validator initialization context .
9292 */
93- private final Set < ConstraintViolation < T >> failingConstraintViolations ;
93+ private final HibernateConstraintValidatorInitializationContext constraintValidatorInitializationContext ;
9494
9595 /**
96- * The constraint factory which should be used in this context .
96+ * Indicates if the tracking of already validated bean should be disabled .
9797 */
98- private final ConstraintValidatorFactory constraintValidatorFactory ;
98+ private final boolean disableAlreadyValidatedBeanTracking ;
9999
100100 /**
101- * Context containing all {@link Validator} level helpers and configuration properties .
101+ * The set of already processed meta constraints per bean - path ({@link BeanPathMetaConstraintProcessedUnit}) .
102102 */
103- protected final ValidatorScopedContext validatorScopedContext ;
103+ @ Lazy
104+ private Set <BeanPathMetaConstraintProcessedUnit > processedPathUnits ;
104105
105106 /**
106- * Allows a JPA provider to decide whether a property should be validated .
107+ * The set of already processed groups per bean ({@link BeanGroupProcessedUnit}) .
107108 */
108- private final TraversableResolver traversableResolver ;
109+ @ Lazy
110+ private Set <BeanGroupProcessedUnit > processedGroupUnits ;
109111
110112 /**
111- * The constraint validator initialization context .
113+ * Maps an object to a list of paths in which it has been validated. The objects are the bean instances .
112114 */
113- private final HibernateConstraintValidatorInitializationContext constraintValidatorInitializationContext ;
115+ @ Lazy
116+ private Map <Object , Set <PathImpl >> processedPathsPerBean ;
114117
115118 /**
116- * Indicates if the tracking of already validated bean should be disabled .
119+ * Contains all failing constraints so far .
117120 */
118- private final boolean disableAlreadyValidatedBeanTracking ;
121+ @ Lazy
122+ private Set <ConstraintViolation <T >> failingConstraintViolations ;
119123
120124 protected AbstractValidationContext (
121125 ConstraintValidatorManager constraintValidatorManager ,
@@ -138,11 +142,6 @@ protected AbstractValidationContext(
138142 this .rootBeanClass = rootBeanClass ;
139143 this .rootBeanMetaData = rootBeanMetaData ;
140144
141- this .processedGroupUnits = new HashSet <>();
142- this .processedPathUnits = new HashSet <>();
143- this .processedPathsPerBean = new IdentityHashMap <>();
144- this .failingConstraintViolations = newHashSet ();
145-
146145 this .disableAlreadyValidatedBeanTracking = disableAlreadyValidatedBeanTracking ;
147146 }
148147
@@ -214,6 +213,10 @@ public void markCurrentBeanAsProcessed(ValueContext<?, ?> valueContext) {
214213
215214 @ Override
216215 public Set <ConstraintViolation <T >> getFailingConstraints () {
216+ if ( failingConstraintViolations == null ) {
217+ return Collections .emptySet ();
218+ }
219+
217220 return failingConstraintViolations ;
218221 }
219222
@@ -235,7 +238,7 @@ public void addConstraintFailure(
235238 // at this point we make a copy of the path to avoid side effects
236239 Path path = PathImpl .createCopy ( constraintViolationCreationContext .getPath () );
237240
238- this . failingConstraintViolations .add (
241+ getInitializedFailingConstraintViolations () .add (
239242 createConstraintViolation (
240243 messageTemplate ,
241244 interpolatedMessage ,
@@ -263,7 +266,7 @@ public boolean hasMetaConstraintBeenProcessed(Object bean, Path path, MetaConstr
263266 return false ;
264267 }
265268
266- return processedPathUnits .contains ( new BeanPathMetaConstraintProcessedUnit ( bean , path , metaConstraint ) );
269+ return getInitializedProcessedPathUnits () .contains ( new BeanPathMetaConstraintProcessedUnit ( bean , path , metaConstraint ) );
267270 }
268271
269272 @ Override
@@ -274,7 +277,7 @@ public void markConstraintProcessed(Object bean, Path path, MetaConstraint<?> me
274277 return ;
275278 }
276279
277- processedPathUnits .add ( new BeanPathMetaConstraintProcessedUnit ( bean , path , metaConstraint ) );
280+ getInitializedProcessedPathUnits () .add ( new BeanPathMetaConstraintProcessedUnit ( bean , path , metaConstraint ) );
278281 }
279282
280283 @ Override
@@ -321,7 +324,7 @@ private String interpolate(
321324 }
322325
323326 private boolean isAlreadyValidatedForPath (Object value , PathImpl path ) {
324- Set <PathImpl > pathSet = processedPathsPerBean .get ( value );
327+ Set <PathImpl > pathSet = getInitializedProcessedPathsPerBean () .get ( value );
325328 if ( pathSet == null ) {
326329 return false ;
327330 }
@@ -352,17 +355,52 @@ private boolean isSubPathOf(Path p1, Path p2) {
352355 }
353356
354357 private boolean isAlreadyValidatedForCurrentGroup (Object value , Class <?> group ) {
355- return processedGroupUnits .contains ( new BeanGroupProcessedUnit ( value , group ) );
358+ return getInitializedProcessedGroupUnits () .contains ( new BeanGroupProcessedUnit ( value , group ) );
356359 }
357360
358361 private void markCurrentBeanAsProcessedForCurrentPath (Object bean , PathImpl path ) {
359362 // HV-1031 The path object is mutated as we traverse the object tree, hence copy it before saving it
360- processedPathsPerBean .computeIfAbsent ( bean , b -> new HashSet <>() )
361- .add ( PathImpl .createCopy ( path ) );
363+ Map <Object , Set <PathImpl >> processedPathsPerBean = getInitializedProcessedPathsPerBean ();
364+
365+ Set <PathImpl > processedPaths = processedPathsPerBean .get ( bean );
366+ if ( processedPaths == null ) {
367+ processedPaths = new HashSet <>();
368+ processedPathsPerBean .put ( bean , processedPaths );
369+ }
370+
371+ processedPaths .add ( PathImpl .createCopy ( path ) );
362372 }
363373
364374 private void markCurrentBeanAsProcessedForCurrentGroup (Object bean , Class <?> group ) {
365- processedGroupUnits .add ( new BeanGroupProcessedUnit ( bean , group ) );
375+ getInitializedProcessedGroupUnits ().add ( new BeanGroupProcessedUnit ( bean , group ) );
376+ }
377+
378+ private Set <BeanPathMetaConstraintProcessedUnit > getInitializedProcessedPathUnits () {
379+ if ( processedPathUnits == null ) {
380+ processedPathUnits = new HashSet <>();
381+ }
382+ return processedPathUnits ;
383+ }
384+
385+ private Set <BeanGroupProcessedUnit > getInitializedProcessedGroupUnits () {
386+ if ( processedGroupUnits == null ) {
387+ processedGroupUnits = new HashSet <>();
388+ }
389+ return processedGroupUnits ;
390+ }
391+
392+ private Map <Object , Set <PathImpl >> getInitializedProcessedPathsPerBean () {
393+ if ( processedPathsPerBean == null ) {
394+ processedPathsPerBean = new IdentityHashMap <>();
395+ }
396+ return processedPathsPerBean ;
397+ }
398+
399+ private Set <ConstraintViolation <T >> getInitializedFailingConstraintViolations () {
400+ if ( failingConstraintViolations == null ) {
401+ failingConstraintViolations = new HashSet <>();
402+ }
403+ return failingConstraintViolations ;
366404 }
367405
368406 private static final class BeanPathMetaConstraintProcessedUnit {
0 commit comments