Skip to content

Commit 3b77c89

Browse files
committed
HV-2004 Add constraint initialization payload
and use it to cache patterns in the predefined factory Signed-off-by: marko-bekhta <[email protected]>
1 parent eb85d34 commit 3b77c89

13 files changed

+213
-23
lines changed

engine/src/main/java/org/hibernate/validator/BaseHibernateValidatorConfiguration.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,30 @@ public interface BaseHibernateValidatorConfiguration<S extends BaseHibernateVali
364364
@Incubating
365365
S constraintValidatorPayload(Object constraintValidatorPayload);
366366

367+
/**
368+
* Allows adding a shared data object which will be available during the constraint validators initialization to all constraints.
369+
* If the method is called multiple times passing different instances of the same class,
370+
* only the instance passed last will be available for that type.
371+
*
372+
* @param constraintValidatorInitializationSharedService the data to retrieve from the constraint validator initializers
373+
* @return {@code this} following the chaining method pattern
374+
* @since 9.1.0
375+
*/
376+
@Incubating
377+
S addConstraintValidatorInitializationSharedData(Object constraintValidatorInitializationSharedService);
378+
379+
/**
380+
* Allows adding a shared data object which will be available during the constraint validators initialization to all constraints.
381+
* If the method is called multiple times passing the same {@code dataClass},
382+
* only the instance passed last will be available for that type.
383+
*
384+
* @param constraintValidatorInitializationSharedData the data to retrieve from the constraint validator initializers
385+
* @return {@code this} following the chaining method pattern
386+
* @since 9.1.0
387+
*/
388+
@Incubating
389+
<T, V extends T> S addConstraintValidatorInitializationSharedData(Class<T> dataClass, V constraintValidatorInitializationSharedData);
390+
367391
/**
368392
* Allows to set a getter property selection strategy defining the rules determining if a method is a getter
369393
* or not.

engine/src/main/java/org/hibernate/validator/constraintvalidation/HibernateConstraintValidatorInitializationContext.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,20 @@ public interface HibernateConstraintValidatorInitializationContext {
5656
*/
5757
@Incubating
5858
Duration getTemporalValidationTolerance();
59+
60+
/**
61+
* Returns an instance of the specified data type or {@code null} if the current context does not
62+
* contain such data.
63+
* The requested data type must match the one with which it was originally added with
64+
* {@link org.hibernate.validator.HibernateValidatorConfiguration#addConstraintValidatorInitializationSharedData(Object)}.
65+
*
66+
* @param type the type of data to retrieve
67+
* @return an instance of the specified type or {@code null} if the current constraint initialization context does not
68+
* contain an instance of such type
69+
*
70+
* @since 9.1.0
71+
* @see org.hibernate.validator.HibernateValidatorConfiguration#addConstraintValidatorInitializationSharedData(Object)
72+
*/
73+
@Incubating
74+
<C> C getSharedData(Class<C> type);
5975
}

engine/src/main/java/org/hibernate/validator/internal/constraintvalidators/bv/PatternValidator.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,35 +8,40 @@
88
import java.util.regex.Matcher;
99
import java.util.regex.PatternSyntaxException;
1010

11-
import jakarta.validation.ConstraintValidator;
1211
import jakarta.validation.ConstraintValidatorContext;
1312
import jakarta.validation.constraints.Pattern;
13+
import jakarta.validation.metadata.ConstraintDescriptor;
1414

15+
import org.hibernate.validator.constraintvalidation.HibernateConstraintValidator;
1516
import org.hibernate.validator.constraintvalidation.HibernateConstraintValidatorContext;
17+
import org.hibernate.validator.constraintvalidation.HibernateConstraintValidatorInitializationContext;
18+
import org.hibernate.validator.internal.engine.constraintvalidation.PatternConstraintInitializer;
1619
import org.hibernate.validator.internal.engine.messageinterpolation.util.InterpolationHelper;
1720
import org.hibernate.validator.internal.util.logging.Log;
1821
import org.hibernate.validator.internal.util.logging.LoggerFactory;
1922

2023
/**
2124
* @author Hardy Ferentschik
2225
*/
23-
public class PatternValidator implements ConstraintValidator<Pattern, CharSequence> {
26+
public class PatternValidator implements HibernateConstraintValidator<Pattern, CharSequence> {
2427

2528
private static final Log LOG = LoggerFactory.make( MethodHandles.lookup() );
2629

2730
private java.util.regex.Pattern pattern;
2831
private String escapedRegexp;
2932

3033
@Override
31-
public void initialize(Pattern parameters) {
34+
public void initialize(ConstraintDescriptor<Pattern> constraintDescriptor, HibernateConstraintValidatorInitializationContext initializationContext) {
35+
Pattern parameters = constraintDescriptor.getAnnotation();
3236
Pattern.Flag[] flags = parameters.flags();
3337
int intFlag = 0;
3438
for ( Pattern.Flag flag : flags ) {
3539
intFlag = intFlag | flag.getValue();
3640
}
3741

3842
try {
39-
pattern = java.util.regex.Pattern.compile( parameters.regexp(), intFlag );
43+
pattern = initializationContext.getSharedData( PatternConstraintInitializer.class )
44+
.of( parameters.regexp(), intFlag );
4045
}
4146
catch (PatternSyntaxException e) {
4247
throw LOG.getInvalidRegularExpressionException( e );

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

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import org.hibernate.validator.cfg.ConstraintMapping;
3838
import org.hibernate.validator.constraintvalidation.spi.DefaultConstraintValidatorFactory;
3939
import org.hibernate.validator.internal.cfg.context.DefaultConstraintMapping;
40+
import org.hibernate.validator.internal.engine.constraintvalidation.HibernateConstraintValidatorInitializationSharedDataManager;
4041
import org.hibernate.validator.internal.engine.resolver.TraversableResolvers;
4142
import org.hibernate.validator.internal.engine.valueextraction.ValueExtractorDescriptor;
4243
import org.hibernate.validator.internal.engine.valueextraction.ValueExtractorManager;
@@ -114,11 +115,12 @@ public abstract class AbstractConfigurationImpl<T extends BaseHibernateValidator
114115
private final Map<ValueExtractorDescriptor.Key, ValueExtractorDescriptor> valueExtractorDescriptors = new HashMap<>();
115116

116117
// HV-specific options
118+
private final HibernateConstraintValidatorInitializationSharedDataManager sharedDataManager;
117119
private final Set<DefaultConstraintMapping> programmaticMappings = newHashSet();
120+
private final MethodValidationConfiguration.Builder methodValidationConfigurationBuilder = new MethodValidationConfiguration.Builder();
118121
private boolean failFast;
119122
private boolean failFastOnPropertyViolation;
120123
private ClassLoader externalClassLoader;
121-
private final MethodValidationConfiguration.Builder methodValidationConfigurationBuilder = new MethodValidationConfiguration.Builder();
122124
private boolean traversableResolverResultCacheEnabled = true;
123125
private ScriptEvaluatorFactory scriptEvaluatorFactory;
124126
private Duration temporalValidationTolerance;
@@ -159,6 +161,7 @@ private AbstractConfigurationImpl() {
159161
this.defaultParameterNameProvider = new DefaultParameterNameProvider();
160162
this.defaultClockProvider = DefaultClockProvider.INSTANCE;
161163
this.defaultPropertyNodeNameProvider = new DefaultPropertyNodeNameProvider();
164+
this.sharedDataManager = new HibernateConstraintValidatorInitializationSharedDataManager();
162165
}
163166

164167
@Override
@@ -352,6 +355,23 @@ public T constraintValidatorPayload(Object constraintValidatorPayload) {
352355
return thisAsT();
353356
}
354357

358+
@Override
359+
public T addConstraintValidatorInitializationSharedData(Object constraintValidatorInitializationSharedData) {
360+
Contracts.assertNotNull( constraintValidatorInitializationSharedData, MESSAGES.parameterMustNotBeNull( "constraintValidatorInitializationSharedData" ) );
361+
362+
this.sharedDataManager.register( constraintValidatorInitializationSharedData );
363+
return thisAsT();
364+
}
365+
366+
@Override
367+
public <V, S extends V> T addConstraintValidatorInitializationSharedData(Class<V> dataClass, S constraintValidatorInitializationSharedData) {
368+
Contracts.assertNotNull( constraintValidatorInitializationSharedData, MESSAGES.parameterMustNotBeNull( "dataClass" ) );
369+
Contracts.assertNotNull( constraintValidatorInitializationSharedData, MESSAGES.parameterMustNotBeNull( "constraintValidatorInitializationSharedData" ) );
370+
this.sharedDataManager.register( dataClass, constraintValidatorInitializationSharedData );
371+
372+
return thisAsT();
373+
}
374+
355375
@Override
356376
public T getterPropertySelectionStrategy(GetterPropertySelectionStrategy getterPropertySelectionStrategy) {
357377
Contracts.assertNotNull( getterPropertySelectionStrategy, MESSAGES.parameterMustNotBeNull( "getterPropertySelectionStrategy" ) );
@@ -548,6 +568,10 @@ public Object getConstraintValidatorPayload() {
548568
return constraintValidatorPayload;
549569
}
550570

571+
public HibernateConstraintValidatorInitializationSharedDataManager getSharedDataManager() {
572+
return sharedDataManager;
573+
}
574+
551575
public GetterPropertySelectionStrategy getGetterPropertySelectionStrategy() {
552576
return getterPropertySelectionStrategy;
553577
}

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.determineShowValidatedValuesInTraceLogs;
2121
import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.determineTemporalValidationTolerance;
2222
import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.determineTraversableResolverResultCacheEnabled;
23+
import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.initializeConstraintValidatorInitializationShareDataManager;
2324
import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.logValidatorFactoryScopedConfiguration;
2425
import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.registerCustomConstraintValidators;
2526
import static org.hibernate.validator.internal.util.CollectionHelper.newArrayList;
@@ -125,8 +126,8 @@ public PredefinedScopeValidatorFactoryImpl(ConfigurationState configurationState
125126
Duration temporalValidationTolerance = determineTemporalValidationTolerance( configurationState, properties );
126127

127128
HibernateConstraintValidatorInitializationContextImpl constraintValidatorInitializationContext = new HibernateConstraintValidatorInitializationContextImpl(
128-
scriptEvaluatorFactory, configurationState.getClockProvider(), temporalValidationTolerance );
129-
129+
scriptEvaluatorFactory, configurationState.getClockProvider(), temporalValidationTolerance,
130+
initializeConstraintValidatorInitializationShareDataManager( hibernateSpecificConfig ) );
130131

131132
this.validatorFactoryScopedContext = new ValidatorFactoryScopedContext(
132133
configurationState.getMessageInterpolator(),

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

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import org.hibernate.validator.cfg.ConstraintMapping;
2222
import org.hibernate.validator.internal.cfg.context.DefaultConstraintMapping;
2323
import org.hibernate.validator.internal.engine.constraintdefinition.ConstraintDefinitionContribution;
24+
import org.hibernate.validator.internal.engine.constraintvalidation.HibernateConstraintValidatorInitializationSharedDataManager;
2425
import org.hibernate.validator.internal.engine.messageinterpolation.DefaultLocaleResolver;
2526
import org.hibernate.validator.internal.engine.scripting.DefaultScriptEvaluatorFactory;
2627
import org.hibernate.validator.internal.metadata.DefaultBeanMetaDataClassNormalizer;
@@ -252,8 +253,7 @@ static Duration determineTemporalValidationTolerance(ConfigurationState configur
252253
}
253254

254255
static Object determineConstraintValidatorPayload(ConfigurationState configurationState) {
255-
if ( configurationState instanceof AbstractConfigurationImpl ) {
256-
AbstractConfigurationImpl<?> hibernateSpecificConfig = (AbstractConfigurationImpl<?>) configurationState;
256+
if ( configurationState instanceof AbstractConfigurationImpl<?> hibernateSpecificConfig ) {
257257
if ( hibernateSpecificConfig.getConstraintValidatorPayload() != null ) {
258258
LOG.logConstraintValidatorPayload( hibernateSpecificConfig.getConstraintValidatorPayload() );
259259
return hibernateSpecificConfig.getConstraintValidatorPayload();
@@ -263,6 +263,20 @@ static Object determineConstraintValidatorPayload(ConfigurationState configurati
263263
return null;
264264
}
265265

266+
static HibernateConstraintValidatorInitializationSharedDataManager initializeConstraintValidatorInitializationShareDataManager(ConfigurationState configurationState) {
267+
HibernateConstraintValidatorInitializationSharedDataManager configured = null;
268+
if ( configurationState instanceof AbstractConfigurationImpl<?> hibernateSpecificConfig ) {
269+
if ( hibernateSpecificConfig.getSharedDataManager() != null ) {
270+
configured = hibernateSpecificConfig.getSharedDataManager();
271+
}
272+
}
273+
if ( configured == null ) {
274+
configured = new HibernateConstraintValidatorInitializationSharedDataManager();
275+
}
276+
277+
return configured.copyWithDefaults();
278+
}
279+
266280
static ExpressionLanguageFeatureLevel determineConstraintExpressionLanguageFeatureLevel(AbstractConfigurationImpl<?> hibernateSpecificConfig,
267281
Map<String, String> properties) {
268282
if ( hibernateSpecificConfig != null && hibernateSpecificConfig.getConstraintExpressionLanguageFeatureLevel() != null ) {

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.determineShowValidatedValuesInTraceLogs;
2121
import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.determineTemporalValidationTolerance;
2222
import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.determineTraversableResolverResultCacheEnabled;
23+
import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.initializeConstraintValidatorInitializationShareDataManager;
2324
import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.logValidatorFactoryScopedConfiguration;
2425
import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.registerCustomConstraintValidators;
2526
import static org.hibernate.validator.internal.util.CollectionHelper.newArrayList;
@@ -168,6 +169,7 @@ public ValidatorFactoryImpl(ConfigurationState configurationState) {
168169
determineTraversableResolverResultCacheEnabled( hibernateSpecificConfig, properties ),
169170
determineShowValidatedValuesInTraceLogs( hibernateSpecificConfig, properties ),
170171
determineConstraintValidatorPayload( hibernateSpecificConfig ),
172+
initializeConstraintValidatorInitializationShareDataManager( hibernateSpecificConfig ),
171173
determineConstraintExpressionLanguageFeatureLevel( hibernateSpecificConfig, properties ),
172174
determineCustomViolationExpressionLanguageFeatureLevel( hibernateSpecificConfig, properties )
173175
);

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
import org.hibernate.validator.constraintvalidation.HibernateConstraintValidatorInitializationContext;
1515
import org.hibernate.validator.internal.engine.constraintvalidation.HibernateConstraintValidatorInitializationContextImpl;
16+
import org.hibernate.validator.internal.engine.constraintvalidation.HibernateConstraintValidatorInitializationSharedDataManager;
1617
import org.hibernate.validator.internal.util.Contracts;
1718
import org.hibernate.validator.internal.util.ExecutableParameterNameProvider;
1819
import org.hibernate.validator.messageinterpolation.ExpressionLanguageFeatureLevel;
@@ -103,13 +104,15 @@ public class ValidatorFactoryScopedContext {
103104
boolean traversableResolverResultCacheEnabled,
104105
boolean showValidatedValuesInTraceLogs,
105106
Object constraintValidatorPayload,
107+
HibernateConstraintValidatorInitializationSharedDataManager constraintValidatorInitializationSharedServiceManager,
106108
ExpressionLanguageFeatureLevel constraintExpressionLanguageFeatureLevel,
107109
ExpressionLanguageFeatureLevel customViolationExpressionLanguageFeatureLevel) {
108110
this( messageInterpolator, traversableResolver, parameterNameProvider, clockProvider, temporalValidationTolerance, scriptEvaluatorFactory, failFast,
109111
failFastOnPropertyViolation, traversableResolverResultCacheEnabled, showValidatedValuesInTraceLogs, constraintValidatorPayload, constraintExpressionLanguageFeatureLevel,
110112
customViolationExpressionLanguageFeatureLevel,
111113
new HibernateConstraintValidatorInitializationContextImpl( scriptEvaluatorFactory, clockProvider,
112-
temporalValidationTolerance ) );
114+
temporalValidationTolerance, constraintValidatorInitializationSharedServiceManager
115+
) );
113116
}
114117

115118
ValidatorFactoryScopedContext(MessageInterpolator messageInterpolator,
@@ -214,7 +217,7 @@ static class Builder {
214217
private ExpressionLanguageFeatureLevel constraintExpressionLanguageFeatureLevel;
215218
private ExpressionLanguageFeatureLevel customViolationExpressionLanguageFeatureLevel;
216219
private boolean showValidatedValuesInTraceLogs;
217-
private HibernateConstraintValidatorInitializationContextImpl constraintValidatorInitializationContext;
220+
private final HibernateConstraintValidatorInitializationContextImpl constraintValidatorInitializationContext;
218221

219222
Builder(ValidatorFactoryScopedContext defaultContext) {
220223
Contracts.assertNotNull( defaultContext, "Default context cannot be null." );
@@ -348,7 +351,8 @@ public ValidatorFactoryScopedContext build() {
348351
constraintValidatorInitializationContext,
349352
scriptEvaluatorFactory,
350353
clockProvider,
351-
temporalValidationTolerance
354+
temporalValidationTolerance,
355+
constraintValidatorInitializationContext.getConstraintValidatorInitializationSharedServiceManager()
352356
)
353357
);
354358
}

engine/src/main/java/org/hibernate/validator/internal/engine/constraintvalidation/HibernateConstraintValidatorInitializationContextImpl.java

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,25 +23,30 @@ public class HibernateConstraintValidatorInitializationContextImpl implements Hi
2323

2424
private final Duration temporalValidationTolerance;
2525

26+
private final HibernateConstraintValidatorInitializationSharedDataManager constraintValidatorInitializationSharedServiceManager;
27+
2628
private final int hashCode;
2729

2830
public HibernateConstraintValidatorInitializationContextImpl(ScriptEvaluatorFactory scriptEvaluatorFactory, ClockProvider clockProvider,
29-
Duration temporalValidationTolerance) {
31+
Duration temporalValidationTolerance, HibernateConstraintValidatorInitializationSharedDataManager constraintValidatorInitializationSharedServiceManager
32+
) {
3033
this.scriptEvaluatorFactory = scriptEvaluatorFactory;
3134
this.clockProvider = clockProvider;
3235
this.temporalValidationTolerance = temporalValidationTolerance;
36+
this.constraintValidatorInitializationSharedServiceManager = constraintValidatorInitializationSharedServiceManager;
3337
this.hashCode = createHashCode();
3438
}
3539

3640
public static HibernateConstraintValidatorInitializationContextImpl of(HibernateConstraintValidatorInitializationContextImpl defaultContext,
37-
ScriptEvaluatorFactory scriptEvaluatorFactory, ClockProvider clockProvider, Duration temporalValidationTolerance) {
41+
ScriptEvaluatorFactory scriptEvaluatorFactory, ClockProvider clockProvider, Duration temporalValidationTolerance,
42+
HibernateConstraintValidatorInitializationSharedDataManager constraintValidatorInitializationSharedServiceManager) {
3843
if ( scriptEvaluatorFactory == defaultContext.scriptEvaluatorFactory
3944
&& clockProvider == defaultContext.clockProvider
4045
&& temporalValidationTolerance.equals( defaultContext.temporalValidationTolerance ) ) {
4146
return defaultContext;
4247
}
4348

44-
return new HibernateConstraintValidatorInitializationContextImpl( scriptEvaluatorFactory, clockProvider, temporalValidationTolerance );
49+
return new HibernateConstraintValidatorInitializationContextImpl( scriptEvaluatorFactory, clockProvider, temporalValidationTolerance, constraintValidatorInitializationSharedServiceManager );
4550
}
4651

4752
@Override
@@ -59,6 +64,15 @@ public Duration getTemporalValidationTolerance() {
5964
return temporalValidationTolerance;
6065
}
6166

67+
@Override
68+
public <C> C getSharedData(Class<C> type) {
69+
return constraintValidatorInitializationSharedServiceManager.retrieve( type );
70+
}
71+
72+
public HibernateConstraintValidatorInitializationSharedDataManager getConstraintValidatorInitializationSharedServiceManager() {
73+
return constraintValidatorInitializationSharedServiceManager;
74+
}
75+
6276
@Override
6377
public boolean equals(Object o) {
6478
if ( this == o ) {

0 commit comments

Comments
 (0)