Skip to content

Commit 3267cb0

Browse files
committed
HV-2004 Use observer to clean up the pattern services
Signed-off-by: marko-bekhta <[email protected]>
1 parent d8f3193 commit 3267cb0

File tree

7 files changed

+50
-31
lines changed

7 files changed

+50
-31
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,8 @@ public interface BaseHibernateValidatorConfiguration<S extends BaseHibernateVali
389389
* Allows adding a payload which will be available during the constraint validators initialization.
390390
* If the method is called multiple times passing different instances of the same class,
391391
* only the payload passed last will be available for that type.
392+
* <p>
393+
* If the added service also implements {@link HibernateValidatorFactoryObserver} such service will be registered as an observer automatically.
392394
*
393395
* @param constraintValidatorInitializationSharedService the payload to retrieve from the constraint validator initializers
394396
* @return {@code this} following the chaining method pattern

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

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -134,10 +134,10 @@ public PredefinedScopeValidatorFactoryImpl(ConfigurationState configurationState
134134
ScriptEvaluatorFactory scriptEvaluatorFactory = determineScriptEvaluatorFactory( configurationState, properties, externalClassLoader );
135135
Duration temporalValidationTolerance = determineTemporalValidationTolerance( configurationState, properties );
136136

137-
PatternConstraintInitializer.CachingPatternConstraintInitializer patternConstraintInitializer = new PatternConstraintInitializer.CachingPatternConstraintInitializer();
137+
List<HibernateValidatorFactoryObserver> sharedServicesObservers = newArrayList();
138138
HibernateConstraintValidatorInitializationContextImpl constraintValidatorInitializationContext = new HibernateConstraintValidatorInitializationContextImpl(
139139
scriptEvaluatorFactory, configurationState.getClockProvider(), temporalValidationTolerance,
140-
determineConstraintValidatorInitializationSharedServices( hibernateSpecificConfig, patternConstraintInitializer ) );
140+
determineConstraintValidatorInitializationSharedServices( hibernateSpecificConfig, PatternConstraintInitializer.predefined(), sharedServicesObservers ) );
141141

142142
this.validatorFactoryScopedContext = new ValidatorFactoryScopedContext(
143143
configurationState.getMessageInterpolator(),
@@ -259,10 +259,7 @@ public PredefinedScopeValidatorFactoryImpl(ConfigurationState configurationState
259259
beanClassesToInitialize
260260
);
261261

262-
// at this point all constraints had to be initialized, so we can clear up the pattern cache:
263-
patternConstraintInitializer.close();
264-
265-
this.hibernateValidatorFactoryObservers = determineHibernateValidatorFactoryObservers( configurationState, properties, externalClassLoader );
262+
this.hibernateValidatorFactoryObservers = determineHibernateValidatorFactoryObservers( sharedServicesObservers, configurationState, properties, externalClassLoader );
266263
safeObserve( hibernateValidatorFactoryObservers, this, OBSERVE_FACTORY_CREATED );
267264

268265
if ( LOG.isDebugEnabled() ) {

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

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ static Object determineConstraintValidatorPayload(ConfigurationState configurati
268268
}
269269

270270
static HibernateConstraintValidatorInitializationSharedServiceManager determineConstraintValidatorInitializationSharedServices(ConfigurationState configurationState,
271-
PatternConstraintInitializer patternConstraintInitializer) {
271+
PatternConstraintInitializer patternConstraintInitializer, List<HibernateValidatorFactoryObserver> sharedServicesObservers) {
272272
HibernateConstraintValidatorInitializationSharedServiceManager configured = null;
273273
if ( configurationState instanceof AbstractConfigurationImpl<?> hibernateSpecificConfig ) {
274274
if ( hibernateSpecificConfig.getConstraintValidatorPayload() != null ) {
@@ -279,9 +279,15 @@ static HibernateConstraintValidatorInitializationSharedServiceManager determineC
279279
configured = new HibernateConstraintValidatorInitializationSharedServiceManager();
280280
}
281281

282-
return configured.immutableWithDefaultServices(
282+
HibernateConstraintValidatorInitializationSharedServiceManager sharedServiceManager = configured.immutableWithDefaultServices(
283283
Map.of( PatternConstraintInitializer.class, patternConstraintInitializer )
284284
);
285+
for ( Object service : sharedServiceManager.registeredServices() ) {
286+
if ( service instanceof HibernateValidatorFactoryObserver observer ) {
287+
sharedServicesObservers.add( observer );
288+
}
289+
}
290+
return sharedServiceManager;
285291
}
286292

287293
static ExpressionLanguageFeatureLevel determineConstraintExpressionLanguageFeatureLevel(AbstractConfigurationImpl<?> hibernateSpecificConfig,
@@ -456,8 +462,9 @@ static boolean determineShowValidatedValuesInTraceLogs(AbstractConfigurationImpl
456462
return tmpShowValidatedValuesInTraceLogging;
457463
}
458464

459-
static List<HibernateValidatorFactoryObserver> determineHibernateValidatorFactoryObservers(ConfigurationState configurationState, Map<String, String> properties, ClassLoader externalClassLoader) {
460-
List<HibernateValidatorFactoryObserver> observers = newArrayList();
465+
static List<HibernateValidatorFactoryObserver> determineHibernateValidatorFactoryObservers(List<HibernateValidatorFactoryObserver> sharedServicesObservers,
466+
ConfigurationState configurationState, Map<String, String> properties, ClassLoader externalClassLoader) {
467+
List<HibernateValidatorFactoryObserver> observers = newArrayList( sharedServicesObservers );
461468
if ( configurationState instanceof AbstractConfigurationImpl<?> hibernateSpecificConfig ) {
462469
observers.addAll( hibernateSpecificConfig.getHibernateValidatorFactoryObservers() );
463470
}

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ public ValidatorFactoryImpl(ConfigurationState configurationState) {
166166
determineAllowParallelMethodsDefineParameterConstraints( hibernateSpecificConfig, properties )
167167
).build();
168168

169+
List<HibernateValidatorFactoryObserver> sharedServicesObservers = newArrayList();
169170
this.validatorFactoryScopedContext = new ValidatorFactoryScopedContext(
170171
configurationState.getMessageInterpolator(),
171172
configurationState.getTraversableResolver(),
@@ -178,7 +179,7 @@ public ValidatorFactoryImpl(ConfigurationState configurationState) {
178179
determineTraversableResolverResultCacheEnabled( hibernateSpecificConfig, properties ),
179180
determineShowValidatedValuesInTraceLogs( hibernateSpecificConfig, properties ),
180181
determineConstraintValidatorPayload( hibernateSpecificConfig ),
181-
determineConstraintValidatorInitializationSharedServices( hibernateSpecificConfig, new PatternConstraintInitializer.SimplePatternConstraintInitializer() ),
182+
determineConstraintValidatorInitializationSharedServices( hibernateSpecificConfig, PatternConstraintInitializer.simple(), sharedServicesObservers ),
182183
determineConstraintExpressionLanguageFeatureLevel( hibernateSpecificConfig, properties ),
183184
determineCustomViolationExpressionLanguageFeatureLevel( hibernateSpecificConfig, properties )
184185
);
@@ -245,7 +246,7 @@ public ValidatorFactoryImpl(ConfigurationState configurationState) {
245246
? hibernateSpecificConfig.getProcessedBeansTrackingVoter()
246247
: new DefaultProcessedBeansTrackingVoter();
247248

248-
this.hibernateValidatorFactoryObservers = determineHibernateValidatorFactoryObservers( configurationState, properties, externalClassLoader );
249+
this.hibernateValidatorFactoryObservers = determineHibernateValidatorFactoryObservers( sharedServicesObservers, configurationState, properties, externalClassLoader );
249250
safeObserve( hibernateValidatorFactoryObservers, this, OBSERVE_FACTORY_CREATED );
250251

251252
if ( LOG.isDebugEnabled() ) {

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
*/
55
package org.hibernate.validator.internal.engine.constraintvalidation;
66

7+
import java.util.Collection;
8+
import java.util.Collections;
79
import java.util.HashMap;
810
import java.util.Map;
911

@@ -47,4 +49,8 @@ public HibernateConstraintValidatorInitializationSharedServiceManager immutableW
4749
Map.copyOf( services )
4850
);
4951
}
52+
53+
public Collection<Object> registeredServices() {
54+
return Collections.unmodifiableCollection( services.values() );
55+
}
5056
}

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

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,37 +8,43 @@
88
import java.util.concurrent.ConcurrentHashMap;
99
import java.util.regex.Pattern;
1010

11-
public interface PatternConstraintInitializer extends AutoCloseable {
11+
import org.hibernate.validator.HibernateValidatorFactory;
12+
import org.hibernate.validator.constraintvalidation.HibernateValidatorFactoryObserver;
1213

13-
Pattern of(String pattern, int flags);
14+
public abstract sealed class PatternConstraintInitializer implements HibernateValidatorFactoryObserver
15+
permits PatternConstraintInitializer.SimplePatternConstraintInitializer, PatternConstraintInitializer.PredefinedPatternConstraintInitializer {
16+
private final Map<PatternKey, Pattern> cache = new ConcurrentHashMap<>();
1417

15-
@Override
16-
default void close() {
18+
public static PatternConstraintInitializer predefined() {
19+
return new PredefinedPatternConstraintInitializer();
1720
}
1821

19-
class SimplePatternConstraintInitializer implements PatternConstraintInitializer {
22+
public static PatternConstraintInitializer simple() {
23+
return new SimplePatternConstraintInitializer();
24+
}
2025

21-
@Override
22-
public Pattern of(String pattern, int flags) {
23-
return Pattern.compile( pattern, flags );
24-
}
26+
public final Pattern of(String pattern, int flags) {
27+
return cache.computeIfAbsent( new PatternKey( pattern, flags ), key -> Pattern.compile( pattern, flags ) );
2528
}
2629

27-
class CachingPatternConstraintInitializer implements PatternConstraintInitializer {
28-
private final Map<PatternKey, Pattern> cache = new ConcurrentHashMap<>();
30+
protected void clearCache() {
31+
cache.clear();
32+
}
2933

34+
static final class SimplePatternConstraintInitializer extends PatternConstraintInitializer {
3035
@Override
31-
public Pattern of(String pattern, int flags) {
32-
return cache.computeIfAbsent( new PatternKey( pattern, flags ), key -> Pattern.compile( pattern, flags ) );
36+
public void factoryClosing(HibernateValidatorFactory factory) {
37+
clearCache();
3338
}
39+
}
3440

41+
static final class PredefinedPatternConstraintInitializer extends PatternConstraintInitializer {
3542
@Override
36-
public void close() {
37-
cache.clear();
38-
}
39-
40-
private record PatternKey(String pattern, int flags) {
43+
public void factoryCreated(HibernateValidatorFactory factory) {
44+
clearCache();
4145
}
4246
}
4347

48+
private record PatternKey(String pattern, int flags) {
49+
}
4450
}

engine/src/test/java/org/hibernate/validator/testutils/ConstraintValidatorInitializationHelper.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ public Duration getTemporalValidationTolerance() {
101101
@Override
102102
public <C> C getConstraintValidatorInitializationSharedService(Class<C> type) {
103103
if ( PatternConstraintInitializer.class.equals( type ) ) {
104-
return (C) new PatternConstraintInitializer.SimplePatternConstraintInitializer();
104+
return (C) PatternConstraintInitializer.simple();
105105
}
106106
return null;
107107
}

0 commit comments

Comments
 (0)