/*
 * Hibernate Validator, declare and validate application constraints
 *
 * License: Apache License, Version 2.0
 * See the license.txt file in the root directory or <http://www.apache.org/licenses/LICENSE-2.0>.
 */
package org.hibernate.validator.internal.engine;

import static org.hibernate.validator.internal.util.CollectionHelper.newHashMap;

import java.lang.annotation.Annotation;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;

import javax.validation.ConstraintValidator;

import org.hibernate.validator.cfg.ConstraintMapping;
import org.hibernate.validator.cfg.context.ConstraintDefinitionContext;
import org.hibernate.validator.internal.util.TypeResolutionHelper;
import org.hibernate.validator.internal.util.privilegedactions.GetInstancesFromServiceLoader;
import org.hibernate.validator.spi.cfg.ConstraintMappingContributor;

import com.fasterxml.classmate.ResolvedType;

Contributor of constraint definitions discovered by the Java service loader mechanism.
Author:Hardy Ferentschik
/** * Contributor of constraint definitions discovered by the Java service loader mechanism. * * @author Hardy Ferentschik */
public class ServiceLoaderBasedConstraintMappingContributor implements ConstraintMappingContributor {
Used for resolving type parameters. Thread-safe.
/** * Used for resolving type parameters. Thread-safe. */
private final TypeResolutionHelper typeResolutionHelper;
The primary class loader passed to the ServiceLoader.

Tries this one then tries the class loader used to load Hibernate Validator classes.

/** * The primary class loader passed to the {@link ServiceLoader}. * <p> * Tries this one then tries the class loader used to load Hibernate Validator classes. */
private final ClassLoader primaryClassLoader; public ServiceLoaderBasedConstraintMappingContributor(TypeResolutionHelper typeResolutionHelper, ClassLoader primaryClassLoader) { this.primaryClassLoader = primaryClassLoader; this.typeResolutionHelper = typeResolutionHelper; } @SuppressWarnings("rawtypes") @Override public void createConstraintMappings(ConstraintMappingBuilder builder) { Map<Class<?>, List<Class<?>>> customValidators = newHashMap(); // find additional constraint validators via the Java ServiceLoader mechanism List<ConstraintValidator> discoveredConstraintValidators = run( GetInstancesFromServiceLoader.action( primaryClassLoader, ConstraintValidator.class ) ); for ( ConstraintValidator constraintValidator : discoveredConstraintValidators ) { Class<? extends ConstraintValidator> constraintValidatorClass = constraintValidator.getClass(); Class<?> annotationType = determineAnnotationType( constraintValidatorClass ); List<Class<?>> validators = customValidators.get( annotationType ); if ( annotationType != null && validators == null ) { validators = new ArrayList<Class<?>>(); customValidators.put( annotationType, validators ); } validators.add( constraintValidatorClass ); } ConstraintMapping constraintMapping = builder.addConstraintMapping(); for ( Map.Entry<Class<?>, List<Class<?>>> entry : customValidators.entrySet() ) { registerConstraintDefinition( constraintMapping, entry.getKey(), entry.getValue() ); } } @SuppressWarnings("unchecked") private <A extends Annotation> void registerConstraintDefinition(ConstraintMapping constraintMapping, Class<?> constraintType, List<Class<?>> validatorTypes) { ConstraintDefinitionContext<A> context = constraintMapping .constraintDefinition( (Class<A>) constraintType ) .includeExistingValidators( true ); for ( Class<?> validatorType : validatorTypes ) { context.validatedBy( (Class<? extends ConstraintValidator<A, ?>>) validatorType ); } } @SuppressWarnings("rawtypes") private Class<?> determineAnnotationType(Class<? extends ConstraintValidator> constraintValidatorClass) { ResolvedType resolvedType = typeResolutionHelper.getTypeResolver() .resolve( constraintValidatorClass ); return resolvedType.typeParametersFor( ConstraintValidator.class ).get( 0 ).getErasedType(); }
Runs the given privileged action, using a privileged block if required.

NOTE: This must never be changed into a publicly available method to avoid execution of arbitrary privileged actions within HV's protection domain.

/** * Runs the given privileged action, using a privileged block if required. * <p> * <b>NOTE:</b> This must never be changed into a publicly available method to avoid execution of arbitrary * privileged actions within HV's protection domain. */
private <T> T run(PrivilegedAction<T> action) { return System.getSecurityManager() != null ? AccessController.doPrivileged( action ) : action.run(); } }