1
7 package org.hibernate.validator.internal.engine;
8
9 import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.determineAllowMultipleCascadedValidationOnReturnValues;
10 import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.determineAllowOverridingMethodAlterParameterConstraint;
11 import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.determineAllowParallelMethodsDefineParameterConstraints;
12 import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.determineBeanMetaDataClassNormalizer;
13 import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.determineConstraintMappings;
14 import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.determineConstraintValidatorPayload;
15 import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.determineExternalClassLoader;
16 import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.determineFailFast;
17 import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.determineScriptEvaluatorFactory;
18 import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.determineTemporalValidationTolerance;
19 import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.determineTraversableResolverResultCacheEnabled;
20 import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.logValidatorFactoryScopedConfiguration;
21 import static org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper.registerCustomConstraintValidators;
22 import static org.hibernate.validator.internal.util.CollectionHelper.newArrayList;
23
24 import java.lang.invoke.MethodHandles;
25 import java.time.Duration;
26 import java.util.Collections;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Set;
30 import java.util.concurrent.ConcurrentHashMap;
31 import java.util.concurrent.ConcurrentMap;
32
33 import javax.validation.ClockProvider;
34 import javax.validation.ConstraintValidatorFactory;
35 import javax.validation.MessageInterpolator;
36 import javax.validation.ParameterNameProvider;
37 import javax.validation.TraversableResolver;
38 import javax.validation.Validator;
39 import javax.validation.ValidatorFactory;
40 import javax.validation.spi.ConfigurationState;
41
42 import org.hibernate.validator.HibernateValidatorContext;
43 import org.hibernate.validator.HibernateValidatorFactory;
44 import org.hibernate.validator.internal.cfg.context.DefaultConstraintMapping;
45 import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorManager;
46 import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorManagerImpl;
47 import org.hibernate.validator.internal.engine.groups.ValidationOrderGenerator;
48 import org.hibernate.validator.internal.engine.valueextraction.ValueExtractorManager;
49 import org.hibernate.validator.internal.metadata.BeanMetaDataManager;
50 import org.hibernate.validator.internal.metadata.BeanMetaDataManagerImpl;
51 import org.hibernate.validator.internal.metadata.core.ConstraintHelper;
52 import org.hibernate.validator.internal.metadata.provider.MetaDataProvider;
53 import org.hibernate.validator.internal.metadata.provider.ProgrammaticMetaDataProvider;
54 import org.hibernate.validator.internal.metadata.provider.XmlMetaDataProvider;
55 import org.hibernate.validator.internal.properties.javabean.JavaBeanHelper;
56 import org.hibernate.validator.internal.util.ExecutableHelper;
57 import org.hibernate.validator.internal.util.ExecutableParameterNameProvider;
58 import org.hibernate.validator.internal.util.TypeResolutionHelper;
59 import org.hibernate.validator.internal.util.logging.Log;
60 import org.hibernate.validator.internal.util.logging.LoggerFactory;
61 import org.hibernate.validator.internal.util.stereotypes.Immutable;
62 import org.hibernate.validator.internal.util.stereotypes.ThreadSafe;
63 import org.hibernate.validator.metadata.BeanMetaDataClassNormalizer;
64 import org.hibernate.validator.spi.properties.GetterPropertySelectionStrategy;
65 import org.hibernate.validator.spi.scripting.ScriptEvaluatorFactory;
66
67
79 public class ValidatorFactoryImpl implements HibernateValidatorFactory {
80
81 private static final Log LOG = LoggerFactory.make( MethodHandles.lookup() );
82
83
86 private final ValidatorFactoryScopedContext validatorFactoryScopedContext;
87
88
92 @Immutable
93 private final Set<DefaultConstraintMapping> constraintMappings;
94
95
98 private final ConstraintCreationContext constraintCreationContext;
99
100
103 private final ExecutableHelper executableHelper;
104
105
108 private final MethodValidationConfiguration methodValidationConfiguration;
109
110
113 private final XmlMetaDataProvider xmlMetaDataProvider;
114
115
122 @ThreadSafe
123 private final ConcurrentMap<BeanMetaDataManagerKey, BeanMetaDataManager> beanMetaDataManagers = new ConcurrentHashMap<>();
124
125 private final JavaBeanHelper javaBeanHelper;
126
127 private final BeanMetaDataClassNormalizer beanMetadataClassNormalizer;
128
129 private final ValidationOrderGenerator validationOrderGenerator;
130
131 public ValidatorFactoryImpl(ConfigurationState configurationState) {
132 ClassLoader externalClassLoader = determineExternalClassLoader( configurationState );
133
134 ConfigurationImpl hibernateSpecificConfig = null;
135 if ( configurationState instanceof ConfigurationImpl ) {
136 hibernateSpecificConfig = (ConfigurationImpl) configurationState;
137 }
138
139 Map<String, String> properties = configurationState.getProperties();
140
141 this.methodValidationConfiguration = new MethodValidationConfiguration.Builder()
142 .allowOverridingMethodAlterParameterConstraint(
143 determineAllowOverridingMethodAlterParameterConstraint( hibernateSpecificConfig, properties )
144 ).allowMultipleCascadedValidationOnReturnValues(
145 determineAllowMultipleCascadedValidationOnReturnValues( hibernateSpecificConfig, properties )
146 ).allowParallelMethodsDefineParameterConstraints(
147 determineAllowParallelMethodsDefineParameterConstraints( hibernateSpecificConfig, properties )
148 ).build();
149
150 this.validatorFactoryScopedContext = new ValidatorFactoryScopedContext(
151 configurationState.getMessageInterpolator(),
152 configurationState.getTraversableResolver(),
153 new ExecutableParameterNameProvider( configurationState.getParameterNameProvider() ),
154 configurationState.getClockProvider(),
155 determineTemporalValidationTolerance( configurationState, properties ),
156 determineScriptEvaluatorFactory( configurationState, properties, externalClassLoader ),
157 determineFailFast( hibernateSpecificConfig, properties ),
158 determineTraversableResolverResultCacheEnabled( hibernateSpecificConfig, properties ),
159 determineConstraintValidatorPayload( hibernateSpecificConfig )
160 );
161
162 ConstraintValidatorManager constraintValidatorManager = new ConstraintValidatorManagerImpl(
163 configurationState.getConstraintValidatorFactory(),
164 this.validatorFactoryScopedContext.getConstraintValidatorInitializationContext()
165 );
166
167 this.validationOrderGenerator = new ValidationOrderGenerator();
168
169 ValueExtractorManager valueExtractorManager = new ValueExtractorManager( configurationState.getValueExtractors() );
170 ConstraintHelper constraintHelper = ConstraintHelper.forAllBuiltinConstraints();
171 TypeResolutionHelper typeResolutionHelper = new TypeResolutionHelper();
172
173 this.constraintCreationContext = new ConstraintCreationContext( constraintHelper, constraintValidatorManager, typeResolutionHelper, valueExtractorManager );
174
175 this.executableHelper = new ExecutableHelper( typeResolutionHelper );
176 this.javaBeanHelper = new JavaBeanHelper( ValidatorFactoryConfigurationHelper.determineGetterPropertySelectionStrategy( hibernateSpecificConfig, properties, externalClassLoader ),
177 ValidatorFactoryConfigurationHelper.determinePropertyNodeNameProvider( hibernateSpecificConfig, properties, externalClassLoader ) );
178 this.beanMetadataClassNormalizer = determineBeanMetaDataClassNormalizer( hibernateSpecificConfig );
179
180
181 if ( configurationState.getMappingStreams().isEmpty() ) {
182 this.xmlMetaDataProvider = null;
183 }
184 else {
185 this.xmlMetaDataProvider = new XmlMetaDataProvider( constraintCreationContext, javaBeanHelper, configurationState.getMappingStreams(), externalClassLoader );
186 }
187
188 this.constraintMappings = Collections.unmodifiableSet(
189 determineConstraintMappings(
190 typeResolutionHelper,
191 configurationState,
192 javaBeanHelper,
193 externalClassLoader
194 )
195 );
196
197 registerCustomConstraintValidators( constraintMappings, constraintHelper );
198
199 if ( LOG.isDebugEnabled() ) {
200 logValidatorFactoryScopedConfiguration( validatorFactoryScopedContext );
201 }
202 }
203
204 @Override
205 public Validator getValidator() {
206 return createValidator(
207 constraintCreationContext.getConstraintValidatorManager().getDefaultConstraintValidatorFactory(),
208 constraintCreationContext,
209 validatorFactoryScopedContext,
210 methodValidationConfiguration
211 );
212 }
213
214 @Override
215 public MessageInterpolator getMessageInterpolator() {
216 return validatorFactoryScopedContext.getMessageInterpolator();
217 }
218
219 @Override
220 public TraversableResolver getTraversableResolver() {
221 return validatorFactoryScopedContext.getTraversableResolver();
222 }
223
224 @Override
225 public ConstraintValidatorFactory getConstraintValidatorFactory() {
226 return constraintCreationContext.getConstraintValidatorManager().getDefaultConstraintValidatorFactory();
227 }
228
229 @Override
230 public ParameterNameProvider getParameterNameProvider() {
231 return validatorFactoryScopedContext.getParameterNameProvider().getDelegate();
232 }
233
234 public ExecutableParameterNameProvider getExecutableParameterNameProvider() {
235 return validatorFactoryScopedContext.getParameterNameProvider();
236 }
237
238 @Override
239 public ClockProvider getClockProvider() {
240 return validatorFactoryScopedContext.getClockProvider();
241 }
242
243 @Override
244 public ScriptEvaluatorFactory getScriptEvaluatorFactory() {
245 return validatorFactoryScopedContext.getScriptEvaluatorFactory();
246 }
247
248 @Override
249 public Duration getTemporalValidationTolerance() {
250 return validatorFactoryScopedContext.getTemporalValidationTolerance();
251 }
252
253 @Override
254 public GetterPropertySelectionStrategy getGetterPropertySelectionStrategy() {
255 return javaBeanHelper.getGetterPropertySelectionStrategy();
256 }
257
258 public boolean isFailFast() {
259 return validatorFactoryScopedContext.isFailFast();
260 }
261
262 MethodValidationConfiguration getMethodValidationConfiguration() {
263 return methodValidationConfiguration;
264 }
265
266 public boolean isTraversableResolverResultCacheEnabled() {
267 return validatorFactoryScopedContext.isTraversableResolverResultCacheEnabled();
268 }
269
270 ConstraintCreationContext getConstraintCreationContext() {
271 return constraintCreationContext;
272 }
273
274 @Override
275 public <T> T unwrap(Class<T> type) {
276
277 if ( type.isAssignableFrom( HibernateValidatorFactory.class ) ) {
278 return type.cast( this );
279 }
280 throw LOG.getTypeNotSupportedForUnwrappingException( type );
281 }
282
283 @Override
284 public HibernateValidatorContext usingContext() {
285 return new ValidatorContextImpl( this );
286 }
287
288 @Override
289 public void close() {
290 constraintCreationContext.getConstraintValidatorManager().clear();
291 constraintCreationContext.getConstraintHelper().clear();
292 for ( BeanMetaDataManager beanMetaDataManager : beanMetaDataManagers.values() ) {
293 beanMetaDataManager.clear();
294 }
295 validatorFactoryScopedContext.getScriptEvaluatorFactory().clear();
296 constraintCreationContext.getValueExtractorManager().clear();
297 }
298
299 public ValidatorFactoryScopedContext getValidatorFactoryScopedContext() {
300 return this.validatorFactoryScopedContext;
301 }
302
303 Validator createValidator(ConstraintValidatorFactory constraintValidatorFactory,
304 ConstraintCreationContext constraintCreationContext,
305 ValidatorFactoryScopedContext validatorFactoryScopedContext,
306 MethodValidationConfiguration methodValidationConfiguration) {
307 BeanMetaDataManager beanMetaDataManager = beanMetaDataManagers.computeIfAbsent(
308 new BeanMetaDataManagerKey( validatorFactoryScopedContext.getParameterNameProvider(), constraintCreationContext.getValueExtractorManager(), methodValidationConfiguration ),
309 key -> new BeanMetaDataManagerImpl(
310 constraintCreationContext,
311 executableHelper,
312 validatorFactoryScopedContext.getParameterNameProvider(),
313 javaBeanHelper,
314 beanMetadataClassNormalizer,
315 validationOrderGenerator,
316 buildMetaDataProviders(),
317 methodValidationConfiguration
318 )
319 );
320
321 return new ValidatorImpl(
322 constraintValidatorFactory,
323 beanMetaDataManager,
324 constraintCreationContext.getValueExtractorManager(),
325 constraintCreationContext.getConstraintValidatorManager(),
326 validationOrderGenerator,
327 validatorFactoryScopedContext
328 );
329 }
330
331 private List<MetaDataProvider> buildMetaDataProviders() {
332 List<MetaDataProvider> metaDataProviders = newArrayList();
333 if ( xmlMetaDataProvider != null ) {
334 metaDataProviders.add( xmlMetaDataProvider );
335 }
336
337 if ( !constraintMappings.isEmpty() ) {
338 metaDataProviders.add(
339 new ProgrammaticMetaDataProvider(
340 constraintCreationContext,
341 constraintMappings
342 )
343 );
344 }
345 return metaDataProviders;
346 }
347
348 private static class BeanMetaDataManagerKey {
349 private final ExecutableParameterNameProvider parameterNameProvider;
350 private final ValueExtractorManager valueExtractorManager;
351 private final MethodValidationConfiguration methodValidationConfiguration;
352 private final int hashCode;
353
354 public BeanMetaDataManagerKey(ExecutableParameterNameProvider parameterNameProvider, ValueExtractorManager valueExtractorManager, MethodValidationConfiguration methodValidationConfiguration) {
355 this.parameterNameProvider = parameterNameProvider;
356 this.valueExtractorManager = valueExtractorManager;
357 this.methodValidationConfiguration = methodValidationConfiguration;
358 this.hashCode = buildHashCode( parameterNameProvider, valueExtractorManager, methodValidationConfiguration );
359 }
360
361 private static int buildHashCode(ExecutableParameterNameProvider parameterNameProvider, ValueExtractorManager valueExtractorManager, MethodValidationConfiguration methodValidationConfiguration) {
362 final int prime = 31;
363 int result = 1;
364 result = prime * result + ( ( methodValidationConfiguration == null ) ? 0 : methodValidationConfiguration.hashCode() );
365 result = prime * result + ( ( parameterNameProvider == null ) ? 0 : parameterNameProvider.hashCode() );
366 result = prime * result + ( ( valueExtractorManager == null ) ? 0 : valueExtractorManager.hashCode() );
367 return result;
368 }
369
370 @Override
371 public int hashCode() {
372 return hashCode;
373 }
374
375 @Override
376 public boolean equals(Object obj) {
377 if ( this == obj ) {
378 return true;
379 }
380 if ( obj == null ) {
381 return false;
382 }
383 if ( getClass() != obj.getClass() ) {
384 return false;
385 }
386 BeanMetaDataManagerKey other = (BeanMetaDataManagerKey) obj;
387
388 return methodValidationConfiguration.equals( other.methodValidationConfiguration ) &&
389 parameterNameProvider.equals( other.parameterNameProvider ) &&
390 valueExtractorManager.equals( other.valueExtractorManager );
391 }
392
393 @Override
394 public String toString() {
395 return "BeanMetaDataManagerKey [parameterNameProvider=" + parameterNameProvider + ", valueExtractorManager=" + valueExtractorManager
396 + ", methodValidationConfiguration=" + methodValidationConfiguration + "]";
397 }
398 }
399 }
400