1
7 package org.hibernate.validator.internal.engine;
8
9 import static org.hibernate.validator.internal.util.CollectionHelper.newHashSet;
10 import static org.hibernate.validator.internal.util.logging.Messages.MESSAGES;
11
12 import java.io.BufferedInputStream;
13 import java.io.IOException;
14 import java.io.InputStream;
15 import java.lang.invoke.MethodHandles;
16 import java.security.AccessController;
17 import java.security.PrivilegedAction;
18 import java.time.Duration;
19 import java.util.Collections;
20 import java.util.HashMap;
21 import java.util.List;
22 import java.util.Locale;
23 import java.util.Map;
24 import java.util.Set;
25 import java.util.stream.Collectors;
26
27 import javax.validation.BootstrapConfiguration;
28 import javax.validation.ClockProvider;
29 import javax.validation.ConstraintValidatorFactory;
30 import javax.validation.MessageInterpolator;
31 import javax.validation.ParameterNameProvider;
32 import javax.validation.TraversableResolver;
33 import javax.validation.ValidationProviderResolver;
34 import javax.validation.ValidatorFactory;
35 import javax.validation.spi.BootstrapState;
36 import javax.validation.spi.ConfigurationState;
37 import javax.validation.spi.ValidationProvider;
38 import javax.validation.valueextraction.ValueExtractor;
39
40 import org.hibernate.validator.BaseHibernateValidatorConfiguration;
41 import org.hibernate.validator.cfg.ConstraintMapping;
42 import org.hibernate.validator.internal.cfg.context.DefaultConstraintMapping;
43 import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorFactoryImpl;
44 import org.hibernate.validator.internal.engine.resolver.TraversableResolvers;
45 import org.hibernate.validator.internal.engine.valueextraction.ValueExtractorDescriptor;
46 import org.hibernate.validator.internal.engine.valueextraction.ValueExtractorManager;
47 import org.hibernate.validator.internal.properties.DefaultGetterPropertySelectionStrategy;
48 import org.hibernate.validator.internal.properties.javabean.JavaBeanHelper;
49 import org.hibernate.validator.internal.util.CollectionHelper;
50 import org.hibernate.validator.internal.util.Contracts;
51 import org.hibernate.validator.internal.util.Version;
52 import org.hibernate.validator.internal.util.logging.Log;
53 import org.hibernate.validator.internal.util.logging.LoggerFactory;
54 import org.hibernate.validator.internal.util.privilegedactions.GetClassLoader;
55 import org.hibernate.validator.internal.util.privilegedactions.GetInstancesFromServiceLoader;
56 import org.hibernate.validator.internal.util.privilegedactions.SetContextClassLoader;
57 import org.hibernate.validator.internal.util.stereotypes.Lazy;
58 import org.hibernate.validator.internal.xml.config.ValidationBootstrapParameters;
59 import org.hibernate.validator.internal.xml.config.ValidationXmlParser;
60 import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator;
61 import org.hibernate.validator.metadata.BeanMetaDataClassNormalizer;
62 import org.hibernate.validator.resourceloading.PlatformResourceBundleLocator;
63 import org.hibernate.validator.spi.messageinterpolation.LocaleResolver;
64 import org.hibernate.validator.spi.nodenameprovider.PropertyNodeNameProvider;
65 import org.hibernate.validator.spi.properties.GetterPropertySelectionStrategy;
66 import org.hibernate.validator.spi.resourceloading.ResourceBundleLocator;
67 import org.hibernate.validator.spi.scripting.ScriptEvaluatorFactory;
68
69
79 public abstract class AbstractConfigurationImpl<T extends BaseHibernateValidatorConfiguration<T>>
80 implements BaseHibernateValidatorConfiguration<T>, ConfigurationState {
81
82 static {
83 Version.touch();
84 }
85
86 private static final Log LOG = LoggerFactory.make( MethodHandles.lookup() );
87
88
89
92 @Lazy
93 private ResourceBundleLocator defaultResourceBundleLocator;
94 @Lazy
95 private MessageInterpolator defaultMessageInterpolator;
96 @Lazy
97 private MessageInterpolator messageInterpolator;
98
99
102 @Lazy
103 private TraversableResolver defaultTraversableResolver;
104
105 private final ConstraintValidatorFactory defaultConstraintValidatorFactory;
106 private final ParameterNameProvider defaultParameterNameProvider;
107 private final ClockProvider defaultClockProvider;
108 private final PropertyNodeNameProvider defaultPropertyNodeNameProvider;
109
110 private ValidationProviderResolver providerResolver;
111 private final ValidationBootstrapParameters validationBootstrapParameters;
112 private boolean ignoreXmlConfiguration = false;
113 private final Set<InputStream> configurationStreams = newHashSet();
114 private BootstrapConfiguration bootstrapConfiguration;
115
116 private final Map<ValueExtractorDescriptor.Key, ValueExtractorDescriptor> valueExtractorDescriptors = new HashMap<>();
117
118
119 private final Set<DefaultConstraintMapping> programmaticMappings = newHashSet();
120 private boolean failFast;
121 private ClassLoader externalClassLoader;
122 private final MethodValidationConfiguration.Builder methodValidationConfigurationBuilder = new MethodValidationConfiguration.Builder();
123 private boolean traversableResolverResultCacheEnabled = true;
124 private ScriptEvaluatorFactory scriptEvaluatorFactory;
125 private Duration temporalValidationTolerance;
126 private Object constraintValidatorPayload;
127 private GetterPropertySelectionStrategy getterPropertySelectionStrategy;
128 private Set<Locale> locales = Collections.emptySet();
129 private Locale defaultLocale = Locale.getDefault();
130 private LocaleResolver localeResolver;
131 private BeanMetaDataClassNormalizer beanMetaDataClassNormalizer;
132
133 protected AbstractConfigurationImpl(BootstrapState state) {
134 this();
135 if ( state.getValidationProviderResolver() == null ) {
136 this.providerResolver = state.getDefaultValidationProviderResolver();
137 }
138 else {
139 this.providerResolver = state.getValidationProviderResolver();
140 }
141 }
142
143 protected AbstractConfigurationImpl(ValidationProvider<?> provider) {
144 this();
145 if ( provider == null ) {
146 throw LOG.getInconsistentConfigurationException();
147 }
148 this.providerResolver = null;
149 validationBootstrapParameters.setProvider( provider );
150 }
151
152 private AbstractConfigurationImpl() {
153 this.validationBootstrapParameters = new ValidationBootstrapParameters();
154
155 this.defaultConstraintValidatorFactory = new ConstraintValidatorFactoryImpl();
156 this.defaultParameterNameProvider = new DefaultParameterNameProvider();
157 this.defaultClockProvider = DefaultClockProvider.INSTANCE;
158 this.defaultPropertyNodeNameProvider = new DefaultPropertyNodeNameProvider();
159 }
160
161 @Override
162 public final T ignoreXmlConfiguration() {
163 ignoreXmlConfiguration = true;
164 return thisAsT();
165 }
166
167 @Override
168 public final T messageInterpolator(MessageInterpolator interpolator) {
169 if ( LOG.isDebugEnabled() ) {
170 if ( interpolator != null ) {
171 LOG.debug( "Setting custom MessageInterpolator of type " + interpolator.getClass().getName() );
172 }
173 }
174 this.validationBootstrapParameters.setMessageInterpolator( interpolator );
175 return thisAsT();
176 }
177
178 @Override
179 public final T traversableResolver(TraversableResolver resolver) {
180 if ( LOG.isDebugEnabled() ) {
181 if ( resolver != null ) {
182 LOG.debug( "Setting custom TraversableResolver of type " + resolver.getClass().getName() );
183 }
184 }
185 this.validationBootstrapParameters.setTraversableResolver( resolver );
186 return thisAsT();
187 }
188
189 @Override
190 public final T enableTraversableResolverResultCache(boolean enabled) {
191 this.traversableResolverResultCacheEnabled = enabled;
192 return thisAsT();
193 }
194
195 public final boolean isTraversableResolverResultCacheEnabled() {
196 return traversableResolverResultCacheEnabled;
197 }
198
199 @Override
200 public final T constraintValidatorFactory(ConstraintValidatorFactory constraintValidatorFactory) {
201 if ( LOG.isDebugEnabled() ) {
202 if ( constraintValidatorFactory != null ) {
203 LOG.debug(
204 "Setting custom ConstraintValidatorFactory of type " + constraintValidatorFactory.getClass()
205 .getName()
206 );
207 }
208 }
209 this.validationBootstrapParameters.setConstraintValidatorFactory( constraintValidatorFactory );
210 return thisAsT();
211 }
212
213 @Override
214 public T parameterNameProvider(ParameterNameProvider parameterNameProvider) {
215 if ( LOG.isDebugEnabled() ) {
216 if ( parameterNameProvider != null ) {
217 LOG.debug(
218 "Setting custom ParameterNameProvider of type " + parameterNameProvider.getClass()
219 .getName()
220 );
221 }
222 }
223 this.validationBootstrapParameters.setParameterNameProvider( parameterNameProvider );
224 return thisAsT();
225 }
226
227 @Override
228 public T clockProvider(ClockProvider clockProvider) {
229 if ( LOG.isDebugEnabled() ) {
230 if ( clockProvider != null ) {
231 LOG.debug( "Setting custom ClockProvider of type " + clockProvider.getClass().getName() );
232 }
233 }
234 this.validationBootstrapParameters.setClockProvider( clockProvider );
235 return thisAsT();
236 }
237
238 @Override
239 public T propertyNodeNameProvider(PropertyNodeNameProvider propertyNodeNameProvider) {
240 if ( LOG.isDebugEnabled() ) {
241 if ( propertyNodeNameProvider != null ) {
242 LOG.debug( "Setting custom PropertyNodeNameProvider of type " + propertyNodeNameProvider.getClass()
243 .getName() );
244 }
245 }
246 this.validationBootstrapParameters.setPropertyNodeNameProvider( propertyNodeNameProvider );
247
248 return thisAsT();
249 }
250
251 @Override
252 public T localeResolver(LocaleResolver localeResolver) {
253 if ( LOG.isDebugEnabled() ) {
254 if ( localeResolver != null ) {
255 LOG.debug( "Setting custom LocaleResolver of type " + localeResolver.getClass()
256 .getName() );
257 }
258 }
259 this.localeResolver = localeResolver;
260
261 return thisAsT();
262 }
263
264 @Override
265 public T addValueExtractor(ValueExtractor<?> extractor) {
266 Contracts.assertNotNull( extractor, MESSAGES.parameterMustNotBeNull( "extractor" ) );
267
268 ValueExtractorDescriptor descriptor = new ValueExtractorDescriptor( extractor );
269 ValueExtractorDescriptor previous = valueExtractorDescriptors.put( descriptor.getKey(), descriptor );
270
271 if ( previous != null ) {
272 throw LOG.getValueExtractorForTypeAndTypeUseAlreadyPresentException( extractor, previous.getValueExtractor() );
273 }
274
275 if ( LOG.isDebugEnabled() ) {
276 LOG.debug( "Adding value extractor " + extractor );
277 }
278
279 return thisAsT();
280 }
281
282 @Override
283 public final T addMapping(InputStream stream) {
284 Contracts.assertNotNull( stream, MESSAGES.inputStreamCannotBeNull() );
285
286 validationBootstrapParameters.addMapping( stream.markSupported() ? stream : new BufferedInputStream( stream ) );
287 return thisAsT();
288 }
289
290 @Override
291 public final T failFast(boolean failFast) {
292 this.failFast = failFast;
293 return thisAsT();
294 }
295
296 @Override
297 public T allowOverridingMethodAlterParameterConstraint(boolean allow) {
298 this.methodValidationConfigurationBuilder.allowOverridingMethodAlterParameterConstraint( allow );
299 return thisAsT();
300 }
301
302 public boolean isAllowOverridingMethodAlterParameterConstraint() {
303 return this.methodValidationConfigurationBuilder.isAllowOverridingMethodAlterParameterConstraint();
304 }
305
306 @Override
307 public T allowMultipleCascadedValidationOnReturnValues(boolean allow) {
308 this.methodValidationConfigurationBuilder.allowMultipleCascadedValidationOnReturnValues( allow );
309 return thisAsT();
310 }
311
312 public boolean isAllowMultipleCascadedValidationOnReturnValues() {
313 return this.methodValidationConfigurationBuilder.isAllowMultipleCascadedValidationOnReturnValues();
314 }
315
316 @Override
317 public T allowParallelMethodsDefineParameterConstraints(boolean allow) {
318 this.methodValidationConfigurationBuilder.allowParallelMethodsDefineParameterConstraints( allow );
319 return thisAsT();
320 }
321
322 @Override
323 public T scriptEvaluatorFactory(ScriptEvaluatorFactory scriptEvaluatorFactory) {
324 Contracts.assertNotNull( scriptEvaluatorFactory, MESSAGES.parameterMustNotBeNull( "scriptEvaluatorFactory" ) );
325
326 this.scriptEvaluatorFactory = scriptEvaluatorFactory;
327 return thisAsT();
328 }
329
330 @Override
331 public T temporalValidationTolerance(Duration temporalValidationTolerance) {
332 Contracts.assertNotNull( temporalValidationTolerance, MESSAGES.parameterMustNotBeNull( "temporalValidationTolerance" ) );
333
334 this.temporalValidationTolerance = temporalValidationTolerance.abs();
335 return thisAsT();
336 }
337
338 @Override
339 public T constraintValidatorPayload(Object constraintValidatorPayload) {
340 Contracts.assertNotNull( constraintValidatorPayload, MESSAGES.parameterMustNotBeNull( "constraintValidatorPayload" ) );
341
342 this.constraintValidatorPayload = constraintValidatorPayload;
343 return thisAsT();
344 }
345
346 @Override
347 public T getterPropertySelectionStrategy(GetterPropertySelectionStrategy getterPropertySelectionStrategy) {
348 Contracts.assertNotNull( getterPropertySelectionStrategy, MESSAGES.parameterMustNotBeNull( "getterPropertySelectionStrategy" ) );
349
350 this.getterPropertySelectionStrategy = getterPropertySelectionStrategy;
351 return thisAsT();
352 }
353
354 @Override
355 public T locales(Set<Locale> locales) {
356 Contracts.assertNotNull( defaultLocale, MESSAGES.parameterMustNotBeNull( "locales" ) );
357
358 this.locales = locales;
359 return thisAsT();
360 }
361
362 @Override
363 public T defaultLocale(Locale defaultLocale) {
364 Contracts.assertNotNull( defaultLocale, MESSAGES.parameterMustNotBeNull( "defaultLocale" ) );
365
366 this.defaultLocale = defaultLocale;
367 return thisAsT();
368 }
369
370 public boolean isAllowParallelMethodsDefineParameterConstraints() {
371 return this.methodValidationConfigurationBuilder.isAllowParallelMethodsDefineParameterConstraints();
372 }
373
374 public MethodValidationConfiguration getMethodValidationConfiguration() {
375 return this.methodValidationConfigurationBuilder.build();
376 }
377
378 @Override
379 public final DefaultConstraintMapping createConstraintMapping() {
380 GetterPropertySelectionStrategy getterPropertySelectionStrategyToUse = null;
381 if ( getterPropertySelectionStrategy == null ) {
382 getterPropertySelectionStrategyToUse = new DefaultGetterPropertySelectionStrategy();
383 }
384 else {
385 getterPropertySelectionStrategyToUse = getterPropertySelectionStrategy;
386 }
387
388 return new DefaultConstraintMapping( new JavaBeanHelper( getterPropertySelectionStrategyToUse, defaultPropertyNodeNameProvider ) );
389 }
390
391 @Override
392 public final T addMapping(ConstraintMapping mapping) {
393 Contracts.assertNotNull( mapping, MESSAGES.parameterMustNotBeNull( "mapping" ) );
394
395 this.programmaticMappings.add( (DefaultConstraintMapping) mapping );
396 return thisAsT();
397 }
398
399 @Override
400 public final T addProperty(String name, String value) {
401 if ( value != null ) {
402 validationBootstrapParameters.addConfigProperty( name, value );
403 }
404 return thisAsT();
405 }
406
407 @Override
408 public T externalClassLoader(ClassLoader externalClassLoader) {
409 Contracts.assertNotNull( externalClassLoader, MESSAGES.parameterMustNotBeNull( "externalClassLoader" ) );
410 this.externalClassLoader = externalClassLoader;
411
412
413 this.messageInterpolator = null;
414
415 return thisAsT();
416 }
417
418 @Override
419 public final ValidatorFactory buildValidatorFactory() {
420 loadValueExtractorsFromServiceLoader();
421 parseValidationXml();
422
423 for ( ValueExtractorDescriptor valueExtractorDescriptor : valueExtractorDescriptors.values() ) {
424 validationBootstrapParameters.addValueExtractorDescriptor( valueExtractorDescriptor );
425 }
426
427 ValidatorFactory factory = null;
428 try {
429 if ( isSpecificProvider() ) {
430 factory = validationBootstrapParameters.getProvider().buildValidatorFactory( this );
431 }
432 else {
433 final Class<? extends ValidationProvider<?>> providerClass = validationBootstrapParameters.getProviderClass();
434 if ( providerClass != null ) {
435 for ( ValidationProvider<?> provider : providerResolver.getValidationProviders() ) {
436 if ( providerClass.isAssignableFrom( provider.getClass() ) ) {
437 factory = provider.buildValidatorFactory( this );
438 break;
439 }
440 }
441 if ( factory == null ) {
442 throw LOG.getUnableToFindProviderException( providerClass );
443 }
444 }
445 else {
446 List<ValidationProvider<?>> providers = providerResolver.getValidationProviders();
447 assert providers.size() != 0;
448 factory = providers.get( 0 ).buildValidatorFactory( this );
449 }
450 }
451 }
452 finally {
453
454 for ( InputStream in : configurationStreams ) {
455 try {
456 in.close();
457 }
458 catch (IOException io) {
459 LOG.unableToCloseInputStream();
460 }
461 }
462 }
463
464 return factory;
465 }
466
467 @Override
468 public final boolean isIgnoreXmlConfiguration() {
469 return ignoreXmlConfiguration;
470 }
471
472 @Override
473 public final MessageInterpolator getMessageInterpolator() {
474
475 MessageInterpolator selectedInterpolator = validationBootstrapParameters.getMessageInterpolator();
476 if ( selectedInterpolator != null ) {
477 return selectedInterpolator;
478 }
479 if ( messageInterpolator == null ) {
480 messageInterpolator = getDefaultMessageInterpolatorConfiguredWithClassLoader();
481 }
482
483 return messageInterpolator;
484 }
485
486 @Override
487 public final Set<InputStream> getMappingStreams() {
488 return validationBootstrapParameters.getMappings();
489 }
490
491 public final boolean getFailFast() {
492 return failFast;
493 }
494
495 @Override
496 public final ConstraintValidatorFactory getConstraintValidatorFactory() {
497 return validationBootstrapParameters.getConstraintValidatorFactory();
498 }
499
500 @Override
501 public final TraversableResolver getTraversableResolver() {
502 return validationBootstrapParameters.getTraversableResolver();
503 }
504
505 @Override
506 public BootstrapConfiguration getBootstrapConfiguration() {
507 if ( bootstrapConfiguration == null ) {
508 bootstrapConfiguration = new ValidationXmlParser( externalClassLoader ).parseValidationXml();
509 }
510 return bootstrapConfiguration;
511 }
512
513 @Override
514 public ParameterNameProvider getParameterNameProvider() {
515 return validationBootstrapParameters.getParameterNameProvider();
516 }
517
518 @Override
519 public ClockProvider getClockProvider() {
520 return validationBootstrapParameters.getClockProvider();
521 }
522
523 public PropertyNodeNameProvider getPropertyNodeNameProvider() {
524 return validationBootstrapParameters.getPropertyNodeNameProvider();
525 }
526
527 public LocaleResolver getLocaleResolver() {
528 return localeResolver;
529 }
530
531 public ScriptEvaluatorFactory getScriptEvaluatorFactory() {
532 return scriptEvaluatorFactory;
533 }
534
535 public Duration getTemporalValidationTolerance() {
536 return temporalValidationTolerance;
537 }
538
539 public Object getConstraintValidatorPayload() {
540 return constraintValidatorPayload;
541 }
542
543 public GetterPropertySelectionStrategy getGetterPropertySelectionStrategy() {
544 return getterPropertySelectionStrategy;
545 }
546
547 @Override
548 public Set<ValueExtractor<?>> getValueExtractors() {
549 return validationBootstrapParameters.getValueExtractorDescriptors()
550 .values()
551 .stream()
552 .map( ValueExtractorDescriptor::getValueExtractor )
553 .collect( Collectors.toSet() );
554 }
555
556 @Override
557 public final Map<String, String> getProperties() {
558 return validationBootstrapParameters.getConfigProperties();
559 }
560
561 public ClassLoader getExternalClassLoader() {
562 return externalClassLoader;
563 }
564
565 @Override
566 public final MessageInterpolator getDefaultMessageInterpolator() {
567 if ( defaultMessageInterpolator == null ) {
568 defaultMessageInterpolator = new ResourceBundleMessageInterpolator( getDefaultResourceBundleLocator(), getAllSupportedLocales(),
569 defaultLocale, ValidatorFactoryConfigurationHelper.determineLocaleResolver( this, this.getProperties(), externalClassLoader ),
570 preloadResourceBundles() );
571 }
572
573 return defaultMessageInterpolator;
574 }
575
576 @Override
577 public final TraversableResolver getDefaultTraversableResolver() {
578 if ( defaultTraversableResolver == null ) {
579 defaultTraversableResolver = TraversableResolvers.getDefault();
580 }
581 return defaultTraversableResolver;
582 }
583
584 @Override
585 public final ConstraintValidatorFactory getDefaultConstraintValidatorFactory() {
586 return defaultConstraintValidatorFactory;
587 }
588
589 @Override
590 public final ResourceBundleLocator getDefaultResourceBundleLocator() {
591 if ( defaultResourceBundleLocator == null ) {
592 defaultResourceBundleLocator = new PlatformResourceBundleLocator(
593 ResourceBundleMessageInterpolator.USER_VALIDATION_MESSAGES, preloadResourceBundles() ? getAllSupportedLocales() : Collections.emptySet() );
594 }
595
596 return defaultResourceBundleLocator;
597 }
598
599 @Override
600 public ParameterNameProvider getDefaultParameterNameProvider() {
601 return defaultParameterNameProvider;
602 }
603
604 @Override
605 public ClockProvider getDefaultClockProvider() {
606 return defaultClockProvider;
607 }
608
609 @Override
610 public Set<ValueExtractor<?>> getDefaultValueExtractors() {
611 return ValueExtractorManager.getDefaultValueExtractors();
612 }
613
614 @Override
615 public T beanMetaDataClassNormalizer(BeanMetaDataClassNormalizer beanMetaDataClassNormalizer) {
616 if ( LOG.isDebugEnabled() ) {
617 if ( beanMetaDataClassNormalizer != null ) {
618 LOG.debug( "Setting custom BeanMetaDataClassNormalizer of type " + beanMetaDataClassNormalizer.getClass()
619 .getName() );
620 }
621 }
622 this.beanMetaDataClassNormalizer = beanMetaDataClassNormalizer;
623 return thisAsT();
624 }
625
626 public BeanMetaDataClassNormalizer getBeanMetaDataClassNormalizer() {
627 return beanMetaDataClassNormalizer;
628 }
629
630
631 public final Set<DefaultConstraintMapping> getProgrammaticMappings() {
632 return programmaticMappings;
633 }
634
635 private boolean isSpecificProvider() {
636 return validationBootstrapParameters.getProvider() != null;
637 }
638
639
642 private void parseValidationXml() {
643 if ( ignoreXmlConfiguration ) {
644 LOG.ignoringXmlConfiguration();
645
646 if ( validationBootstrapParameters.getTraversableResolver() == null ) {
647 validationBootstrapParameters.setTraversableResolver( getDefaultTraversableResolver() );
648 }
649 if ( validationBootstrapParameters.getConstraintValidatorFactory() == null ) {
650 validationBootstrapParameters.setConstraintValidatorFactory( defaultConstraintValidatorFactory );
651 }
652 if ( validationBootstrapParameters.getParameterNameProvider() == null ) {
653 validationBootstrapParameters.setParameterNameProvider( defaultParameterNameProvider );
654 }
655 if ( validationBootstrapParameters.getClockProvider() == null ) {
656 validationBootstrapParameters.setClockProvider( defaultClockProvider );
657 }
658 if ( validationBootstrapParameters.getPropertyNodeNameProvider() == null ) {
659 validationBootstrapParameters.setPropertyNodeNameProvider( defaultPropertyNodeNameProvider );
660 }
661 }
662 else {
663 ValidationBootstrapParameters xmlParameters = new ValidationBootstrapParameters(
664 getBootstrapConfiguration(), externalClassLoader
665 );
666 applyXmlSettings( xmlParameters );
667 }
668 }
669
670 @SuppressWarnings("rawtypes")
671 private void loadValueExtractorsFromServiceLoader() {
672 List<ValueExtractor> valueExtractors = run( GetInstancesFromServiceLoader.action(
673 externalClassLoader != null ? externalClassLoader : run( GetClassLoader.fromContext() ),
674 ValueExtractor.class
675 ) );
676
677 for ( ValueExtractor<?> valueExtractor : valueExtractors ) {
678 validationBootstrapParameters.addValueExtractorDescriptor( new ValueExtractorDescriptor( valueExtractor ) );
679 }
680 }
681
682 private void applyXmlSettings(ValidationBootstrapParameters xmlParameters) {
683 validationBootstrapParameters.setProviderClass( xmlParameters.getProviderClass() );
684
685 if ( validationBootstrapParameters.getMessageInterpolator() == null ) {
686 if ( xmlParameters.getMessageInterpolator() != null ) {
687 validationBootstrapParameters.setMessageInterpolator( xmlParameters.getMessageInterpolator() );
688 }
689 }
690
691 if ( validationBootstrapParameters.getTraversableResolver() == null ) {
692 if ( xmlParameters.getTraversableResolver() != null ) {
693 validationBootstrapParameters.setTraversableResolver( xmlParameters.getTraversableResolver() );
694 }
695 else {
696 validationBootstrapParameters.setTraversableResolver( getDefaultTraversableResolver() );
697 }
698 }
699
700 if ( validationBootstrapParameters.getConstraintValidatorFactory() == null ) {
701 if ( xmlParameters.getConstraintValidatorFactory() != null ) {
702 validationBootstrapParameters.setConstraintValidatorFactory(
703 xmlParameters.getConstraintValidatorFactory()
704 );
705 }
706 else {
707 validationBootstrapParameters.setConstraintValidatorFactory( defaultConstraintValidatorFactory );
708 }
709 }
710
711 if ( validationBootstrapParameters.getParameterNameProvider() == null ) {
712 if ( xmlParameters.getParameterNameProvider() != null ) {
713 validationBootstrapParameters.setParameterNameProvider( xmlParameters.getParameterNameProvider() );
714 }
715 else {
716 validationBootstrapParameters.setParameterNameProvider( defaultParameterNameProvider );
717 }
718 }
719
720 if ( validationBootstrapParameters.getClockProvider() == null ) {
721 if ( xmlParameters.getClockProvider() != null ) {
722 validationBootstrapParameters.setClockProvider( xmlParameters.getClockProvider() );
723 }
724 else {
725 validationBootstrapParameters.setClockProvider( defaultClockProvider );
726 }
727 }
728
729 if ( validationBootstrapParameters.getPropertyNodeNameProvider() == null ) {
730 if ( xmlParameters.getPropertyNodeNameProvider() != null ) {
731 validationBootstrapParameters.setPropertyNodeNameProvider(
732 xmlParameters.getPropertyNodeNameProvider() );
733 }
734 else {
735 validationBootstrapParameters.setPropertyNodeNameProvider( defaultPropertyNodeNameProvider );
736 }
737 }
738
739 for ( ValueExtractorDescriptor valueExtractorDescriptor : xmlParameters.getValueExtractorDescriptors().values() ) {
740 validationBootstrapParameters.addValueExtractorDescriptor( valueExtractorDescriptor );
741 }
742
743 validationBootstrapParameters.addAllMappings( xmlParameters.getMappings() );
744 configurationStreams.addAll( xmlParameters.getMappings() );
745
746 for ( Map.Entry<String, String> entry : xmlParameters.getConfigProperties().entrySet() ) {
747 if ( validationBootstrapParameters.getConfigProperties().get( entry.getKey() ) == null ) {
748 validationBootstrapParameters.addConfigProperty( entry.getKey(), entry.getValue() );
749 }
750 }
751 }
752
753
756 private MessageInterpolator getDefaultMessageInterpolatorConfiguredWithClassLoader() {
757 if ( externalClassLoader != null ) {
758 PlatformResourceBundleLocator userResourceBundleLocator = new PlatformResourceBundleLocator(
759 ResourceBundleMessageInterpolator.USER_VALIDATION_MESSAGES,
760 preloadResourceBundles() ? getAllSupportedLocales() : Collections.emptySet(),
761 externalClassLoader
762 );
763 PlatformResourceBundleLocator contributorResourceBundleLocator = new PlatformResourceBundleLocator(
764 ResourceBundleMessageInterpolator.CONTRIBUTOR_VALIDATION_MESSAGES,
765 preloadResourceBundles() ? getAllSupportedLocales() : Collections.emptySet(),
766 externalClassLoader,
767 true
768 );
769
770
771
772 final ClassLoader originalContextClassLoader = run( GetClassLoader.fromContext() );
773
774 try {
775 run( SetContextClassLoader.action( externalClassLoader ) );
776 return new ResourceBundleMessageInterpolator(
777 userResourceBundleLocator,
778 contributorResourceBundleLocator,
779 getAllSupportedLocales(),
780 defaultLocale,
781 ValidatorFactoryConfigurationHelper.determineLocaleResolver( this, this.getProperties(), externalClassLoader ),
782 preloadResourceBundles()
783 );
784 }
785 finally {
786 run( SetContextClassLoader.action( originalContextClassLoader ) );
787 }
788 }
789 else {
790 return getDefaultMessageInterpolator();
791 }
792 }
793
794 private Set<Locale> getAllSupportedLocales() {
795 if ( locales.isEmpty() ) {
796 return Collections.singleton( defaultLocale );
797 }
798 if ( locales.contains( defaultLocale ) ) {
799 return locales;
800 }
801
802 Set<Locale> allLocales = CollectionHelper.newHashSet( locales.size() + 1 );
803 allLocales.addAll( locales );
804 allLocales.add( defaultLocale );
805 return allLocales;
806 }
807
808 protected abstract boolean preloadResourceBundles();
809
810 @SuppressWarnings("unchecked")
811 protected T thisAsT() {
812 return (T) this;
813 }
814
815
821 private static <T> T run(PrivilegedAction<T> action) {
822 return System.getSecurityManager() != null ? AccessController.doPrivileged( action ) : action.run();
823 }
824 }
825