Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit c5b8c43

Browse files
HV-2004 Add constraint initialization payload
and use it to cache patterns in the predefined factory Signed-off-by: marko-bekhta <marko.prykladna@gmail.com>
1 parent 09c7ebb commit c5b8c43

File tree

13 files changed

+171
-22
lines changed

13 files changed

+171
-22
lines changed

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

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

367+
/**
368+
* Allows adding a payload which will be available during the constraint validators initialization.
369+
* If the method is called multiple times passing different instances of the same class,
370+
* only the payload passed last will be available for that type.
371+
*
372+
* @param constraintValidatorInitializationPayload the payload 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 addConstraintValidatorInitializationPayload(Object constraintValidatorInitializationPayload);
378+
367379
/**
368380
* Allows to set a getter property selection strategy defining the rules determining if a method is a getter
369381
* or not.

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,18 @@ public interface HibernateConstraintValidatorInitializationContext {
5656
*/
5757
@Incubating
5858
Duration getTemporalValidationTolerance();
59+
60+
/**
61+
* Returns an instance of the specified type or {@code null} if the current constraint initialization context does not
62+
* contain an instance of such type.
63+
*
64+
* @param type the type of payload to retrieve
65+
* @return an instance of the specified type or {@code null} if the current constraint initialization context does not
66+
* contain an instance of such type
67+
*
68+
* @since 9.1.0
69+
* @see org.hibernate.validator.HibernateValidatorConfiguration#addConstraintValidatorInitializationPayload(Object)
70+
*/
71+
@Incubating
72+
<C> C getConstraintValidatorInitializationPayload(Class<C> type);
5973
}

‎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.getConstraintValidatorInitializationPayload( 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: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55
package org.hibernate.validator.internal.engine;
66

7+
import static org.hibernate.validator.internal.util.CollectionHelper.newHashMap;
78
import static org.hibernate.validator.internal.util.CollectionHelper.newHashSet;
89
import static org.hibernate.validator.internal.util.logging.Messages.MESSAGES;
910

@@ -123,6 +124,7 @@ public abstract class AbstractConfigurationImpl<T extends BaseHibernateValidator
123124
private ScriptEvaluatorFactory scriptEvaluatorFactory;
124125
private Duration temporalValidationTolerance;
125126
private Object constraintValidatorPayload;
127+
private final Map<Class<?>, Object> constraintValidatorInitializationPayload = newHashMap();
126128
private GetterPropertySelectionStrategy getterPropertySelectionStrategy;
127129
private Set<Locale> locales = Collections.emptySet();
128130
private Locale defaultLocale = Locale.getDefault();
@@ -352,6 +354,14 @@ public T constraintValidatorPayload(Object constraintValidatorPayload) {
352354
return thisAsT();
353355
}
354356

357+
@Override
358+
public T addConstraintValidatorInitializationPayload(Object constraintValidatorInitializationPayload) {
359+
Contracts.assertNotNull( constraintValidatorInitializationPayload, MESSAGES.parameterMustNotBeNull( "constraintValidatorInitializationPayload" ) );
360+
361+
this.constraintValidatorInitializationPayload.put( constraintValidatorInitializationPayload.getClass(), constraintValidatorInitializationPayload );
362+
return thisAsT();
363+
}
364+
355365
@Override
356366
public T getterPropertySelectionStrategy(GetterPropertySelectionStrategy getterPropertySelectionStrategy) {
357367
Contracts.assertNotNull( getterPropertySelectionStrategy, MESSAGES.parameterMustNotBeNull( "getterPropertySelectionStrategy" ) );
@@ -548,6 +558,10 @@ public Object getConstraintValidatorPayload() {
548558
return constraintValidatorPayload;
549559
}
550560

561+
public Map<Class<?>, Object> getConstraintValidatorInitializationPayload() {
562+
return constraintValidatorInitializationPayload;
563+
}
564+
551565
public GetterPropertySelectionStrategy getGetterPropertySelectionStrategy() {
552566
return getterPropertySelectionStrategy;
553567
}

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.determineBeanMetaDataClassNormalizer;
1111
import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.determineConstraintExpressionLanguageFeatureLevel;
1212
import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.determineConstraintMappings;
13+
import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.determineConstraintValidatorInitializationPayload;
1314
import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.determineConstraintValidatorPayload;
1415
import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.determineCustomViolationExpressionLanguageFeatureLevel;
1516
import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.determineExternalClassLoader;
@@ -47,6 +48,7 @@
4748
import org.hibernate.validator.internal.cfg.context.DefaultConstraintMapping;
4849
import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorManager;
4950
import org.hibernate.validator.internal.engine.constraintvalidation.HibernateConstraintValidatorInitializationContextImpl;
51+
import org.hibernate.validator.internal.engine.constraintvalidation.PatternConstraintInitializer;
5052
import org.hibernate.validator.internal.engine.constraintvalidation.PredefinedScopeConstraintValidatorManagerImpl;
5153
import org.hibernate.validator.internal.engine.groups.ValidationOrderGenerator;
5254
import org.hibernate.validator.internal.engine.tracking.DefaultProcessedBeansTrackingVoter;
@@ -124,9 +126,10 @@ public PredefinedScopeValidatorFactoryImpl(ConfigurationState configurationState
124126
ScriptEvaluatorFactory scriptEvaluatorFactory = determineScriptEvaluatorFactory( configurationState, properties, externalClassLoader );
125127
Duration temporalValidationTolerance = determineTemporalValidationTolerance( configurationState, properties );
126128

129+
PatternConstraintInitializer.CachingPatternConstraintInitializer patternConstraintInitializer = new PatternConstraintInitializer.CachingPatternConstraintInitializer();
127130
HibernateConstraintValidatorInitializationContextImpl constraintValidatorInitializationContext = new HibernateConstraintValidatorInitializationContextImpl(
128-
scriptEvaluatorFactory, configurationState.getClockProvider(), temporalValidationTolerance );
129-
131+
scriptEvaluatorFactory, configurationState.getClockProvider(), temporalValidationTolerance,
132+
determineConstraintValidatorInitializationPayload( hibernateSpecificConfig, patternConstraintInitializer ) );
130133

131134
this.validatorFactoryScopedContext = new ValidatorFactoryScopedContext(
132135
configurationState.getMessageInterpolator(),
@@ -248,6 +251,9 @@ public PredefinedScopeValidatorFactoryImpl(ConfigurationState configurationState
248251
beanClassesToInitialize
249252
);
250253

254+
// at this point all constraints had to be initialized, so we can clear up the pattern cache:
255+
patternConstraintInitializer.close();
256+
251257
if ( LOG.isDebugEnabled() ) {
252258
logValidatorFactoryScopedConfiguration( validatorFactoryScopedContext );
253259
}

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

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import java.lang.invoke.MethodHandles;
1212
import java.time.Duration;
1313
import java.util.Collections;
14+
import java.util.HashMap;
1415
import java.util.List;
1516
import java.util.Map;
1617
import java.util.Set;
@@ -21,6 +22,7 @@
2122
import org.hibernate.validator.cfg.ConstraintMapping;
2223
import org.hibernate.validator.internal.cfg.context.DefaultConstraintMapping;
2324
import org.hibernate.validator.internal.engine.constraintdefinition.ConstraintDefinitionContribution;
25+
import org.hibernate.validator.internal.engine.constraintvalidation.PatternConstraintInitializer;
2426
import org.hibernate.validator.internal.engine.messageinterpolation.DefaultLocaleResolver;
2527
import org.hibernate.validator.internal.engine.scripting.DefaultScriptEvaluatorFactory;
2628
import org.hibernate.validator.internal.metadata.DefaultBeanMetaDataClassNormalizer;
@@ -252,8 +254,7 @@ static Duration determineTemporalValidationTolerance(ConfigurationState configur
252254
}
253255

254256
static Object determineConstraintValidatorPayload(ConfigurationState configurationState) {
255-
if ( configurationState instanceof AbstractConfigurationImpl ) {
256-
AbstractConfigurationImpl<?> hibernateSpecificConfig = (AbstractConfigurationImpl<?>) configurationState;
257+
if ( configurationState instanceof AbstractConfigurationImpl<?> hibernateSpecificConfig ) {
257258
if ( hibernateSpecificConfig.getConstraintValidatorPayload() != null ) {
258259
LOG.logConstraintValidatorPayload( hibernateSpecificConfig.getConstraintValidatorPayload() );
259260
return hibernateSpecificConfig.getConstraintValidatorPayload();
@@ -263,6 +264,23 @@ static Object determineConstraintValidatorPayload(ConfigurationState configurati
263264
return null;
264265
}
265266

267+
static Map<Class<?>, Object> determineConstraintValidatorInitializationPayload(ConfigurationState configurationState, PatternConstraintInitializer patternConstraintInitializer) {
268+
if ( configurationState instanceof AbstractConfigurationImpl<?> hibernateSpecificConfig ) {
269+
if ( hibernateSpecificConfig.getConstraintValidatorPayload() != null ) {
270+
Map<Class<?>, Object> configured = hibernateSpecificConfig.getConstraintValidatorInitializationPayload();
271+
Map<Class<?>, Object> payload = new HashMap<>();
272+
payload.put( PatternConstraintInitializer.class, patternConstraintInitializer );
273+
if ( configured != null ) {
274+
payload.putAll( configured );
275+
}
276+
LOG.logConstraintValidatorInitializationPayload( payload );
277+
return Collections.unmodifiableMap( payload );
278+
}
279+
}
280+
281+
return Map.of( PatternConstraintInitializer.class, patternConstraintInitializer );
282+
}
283+
266284
static ExpressionLanguageFeatureLevel determineConstraintExpressionLanguageFeatureLevel(AbstractConfigurationImpl<?> hibernateSpecificConfig,
267285
Map<String, String> properties) {
268286
if ( hibernateSpecificConfig != null && hibernateSpecificConfig.getConstraintExpressionLanguageFeatureLevel() != null ) {

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.determineBeanMetaDataClassNormalizer;
1111
import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.determineConstraintExpressionLanguageFeatureLevel;
1212
import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.determineConstraintMappings;
13+
import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.determineConstraintValidatorInitializationPayload;
1314
import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.determineConstraintValidatorPayload;
1415
import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.determineCustomViolationExpressionLanguageFeatureLevel;
1516
import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.determineExternalClassLoader;
@@ -47,6 +48,7 @@
4748
import org.hibernate.validator.internal.cfg.context.DefaultConstraintMapping;
4849
import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorManager;
4950
import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorManagerImpl;
51+
import org.hibernate.validator.internal.engine.constraintvalidation.PatternConstraintInitializer;
5052
import org.hibernate.validator.internal.engine.groups.ValidationOrderGenerator;
5153
import org.hibernate.validator.internal.engine.tracking.DefaultProcessedBeansTrackingVoter;
5254
import org.hibernate.validator.internal.engine.valueextraction.ValueExtractorManager;
@@ -168,6 +170,7 @@ public ValidatorFactoryImpl(ConfigurationState configurationState) {
168170
determineTraversableResolverResultCacheEnabled( hibernateSpecificConfig, properties ),
169171
determineShowValidatedValuesInTraceLogs( hibernateSpecificConfig, properties ),
170172
determineConstraintValidatorPayload( hibernateSpecificConfig ),
173+
determineConstraintValidatorInitializationPayload( hibernateSpecificConfig, new PatternConstraintInitializer.SimplePatternConstraintInitializer() ),
171174
determineConstraintExpressionLanguageFeatureLevel( hibernateSpecificConfig, properties ),
172175
determineCustomViolationExpressionLanguageFeatureLevel( hibernateSpecificConfig, properties )
173176
);

‎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
@@ -5,6 +5,7 @@
55
package org.hibernate.validator.internal.engine;
66

77
import java.time.Duration;
8+
import java.util.Map;
89

910
import jakarta.validation.ClockProvider;
1011
import jakarta.validation.MessageInterpolator;
@@ -103,13 +104,15 @@ public class ValidatorFactoryScopedContext {
103104
boolean traversableResolverResultCacheEnabled,
104105
boolean showValidatedValuesInTraceLogs,
105106
Object constraintValidatorPayload,
107+
Map<Class<?>, Object> constraintValidatorInitializationPayload,
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, constraintValidatorInitializationPayload
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 finalHibernateConstraintValidatorInitializationContextImpl 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.getConstraintValidatorInitializationPayload()
352356
)
353357
);
354358
}

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

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
package org.hibernate.validator.internal.engine.constraintvalidation;
66

77
import java.time.Duration;
8+
import java.util.Map;
89

910
import jakarta.validation.ClockProvider;
1011

@@ -23,25 +24,29 @@ public class HibernateConstraintValidatorInitializationContextImpl implements Hi
2324

2425
private final Duration temporalValidationTolerance;
2526

27+
private final Map<Class<?>, Object> constraintValidatorInitializationPayload;
28+
2629
private final int hashCode;
2730

2831
public HibernateConstraintValidatorInitializationContextImpl(ScriptEvaluatorFactory scriptEvaluatorFactory, ClockProvider clockProvider,
29-
Duration temporalValidationTolerance) {
32+
Duration temporalValidationTolerance, Map<Class<?>, Object> constraintValidatorInitializationPayload
33+
) {
3034
this.scriptEvaluatorFactory = scriptEvaluatorFactory;
3135
this.clockProvider = clockProvider;
3236
this.temporalValidationTolerance = temporalValidationTolerance;
37+
this.constraintValidatorInitializationPayload = constraintValidatorInitializationPayload;
3338
this.hashCode = createHashCode();
3439
}
3540

3641
public static HibernateConstraintValidatorInitializationContextImpl of(HibernateConstraintValidatorInitializationContextImpl defaultContext,
37-
ScriptEvaluatorFactory scriptEvaluatorFactory, ClockProvider clockProvider, Duration temporalValidationTolerance) {
42+
ScriptEvaluatorFactory scriptEvaluatorFactory, ClockProvider clockProvider, Duration temporalValidationTolerance, Map<Class<?>, Object> constraintValidatorInitializationPayload) {
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, constraintValidatorInitializationPayload );
4550
}
4651

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

67+
@SuppressWarnings("unchecked") // because of the way we populate that map
68+
@Override
69+
public <C> C getConstraintValidatorInitializationPayload(Class<C> type) {
70+
return ( (C) constraintValidatorInitializationPayload.get( type ) );
71+
}
72+
73+
public Map<Class<?>, Object> getConstraintValidatorInitializationPayload() {
74+
return constraintValidatorInitializationPayload;
75+
}
76+
6277
@Override
6378
public boolean equals(Object o) {
6479
if ( this == o ) {
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.validator.internal.engine.constraintvalidation;
6+
7+
import java.util.Map;
8+
import java.util.concurrent.ConcurrentHashMap;
9+
import java.util.regex.Pattern;
10+
11+
public interface PatternConstraintInitializer extends AutoCloseable {
12+
13+
Pattern of(String pattern, int flags);
14+
15+
@Override
16+
default void close() {
17+
}
18+
19+
class SimplePatternConstraintInitializer implements PatternConstraintInitializer {
20+
21+
@Override
22+
public Pattern of(String pattern, int flags) {
23+
return Pattern.compile( pattern, flags );
24+
}
25+
}
26+
27+
class CachingPatternConstraintInitializer implements PatternConstraintInitializer {
28+
private final Map<PatternKey, Pattern> cache = new ConcurrentHashMap<PatternKey, Pattern>();
29+
30+
@Override
31+
public Pattern of(String pattern, int flags) {
32+
return cache.computeIfAbsent( new PatternKey( pattern, flags ), key -> Pattern.compile( pattern, flags ) );
33+
}
34+
35+
@Override
36+
public void close() {
37+
cache.clear();
38+
}
39+
40+
private record PatternKey(String pattern, int flags) {
41+
}
42+
}
43+
44+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /