org.hibernate.validator.internal.metadata.provider.ProgrammaticMetaDataProvider Maven / Gradle / Ivy
Show all versions of bean-validator Show documentation
/*
* Hibernate Validator, declare and validate application constraints
*
* License: Apache License, Version 2.0
* See the license.txt file in the root directory or .
*/
package org.hibernate.validator.internal.metadata.provider;
import static org.hibernate.validator.internal.util.CollectionHelper.newHashSet;
import java.lang.invoke.MethodHandles;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.hibernate.validator.internal.cfg.context.DefaultConstraintMapping;
import org.hibernate.validator.internal.engine.valueextraction.ValueExtractorManager;
import org.hibernate.validator.internal.metadata.core.AnnotationProcessingOptions;
import org.hibernate.validator.internal.metadata.core.AnnotationProcessingOptionsImpl;
import org.hibernate.validator.internal.metadata.core.ConstraintHelper;
import org.hibernate.validator.internal.metadata.raw.BeanConfiguration;
import org.hibernate.validator.internal.util.CollectionHelper;
import org.hibernate.validator.internal.util.Contracts;
import org.hibernate.validator.internal.util.TypeResolutionHelper;
import org.hibernate.validator.internal.util.logging.Log;
import org.hibernate.validator.internal.util.logging.LoggerFactory;
import org.hibernate.validator.internal.util.stereotypes.Immutable;
/**
* A {@link MetaDataProvider} based on the programmatic constraint API.
*
* @author Gunnar Morling
*/
public class ProgrammaticMetaDataProvider implements MetaDataProvider {
private static final Log LOG = LoggerFactory.make( MethodHandles.lookup() );
// cached against the fqcn of a class. not a class instance itself (HV-479)
@Immutable
private final Map> configuredBeans;
private final AnnotationProcessingOptions annotationProcessingOptions;
public ProgrammaticMetaDataProvider(ConstraintHelper constraintHelper,
TypeResolutionHelper typeResolutionHelper,
ValueExtractorManager valueExtractorManager,
Set constraintMappings) {
Contracts.assertNotNull( constraintMappings );
configuredBeans = CollectionHelper.toImmutableMap(
createBeanConfigurations( constraintMappings, constraintHelper, typeResolutionHelper, valueExtractorManager )
);
assertUniquenessOfConfiguredTypes( constraintMappings );
annotationProcessingOptions = mergeAnnotationProcessingOptions( constraintMappings );
}
private static void assertUniquenessOfConfiguredTypes(Set mappings) {
Set> allConfiguredTypes = newHashSet();
for ( DefaultConstraintMapping constraintMapping : mappings ) {
for ( Class configuredType : constraintMapping.getConfiguredTypes() ) {
if ( allConfiguredTypes.contains( configuredType ) ) {
throw LOG.getBeanClassHasAlreadyBeConfiguredViaProgrammaticApiException( configuredType );
}
}
allConfiguredTypes.addAll( constraintMapping.getConfiguredTypes() );
}
}
private static Map> createBeanConfigurations(Set mappings, ConstraintHelper constraintHelper,
TypeResolutionHelper typeResolutionHelper, ValueExtractorManager valueExtractorManager) {
final Map> configuredBeans = new HashMap<>();
for ( DefaultConstraintMapping mapping : mappings ) {
Set> beanConfigurations = mapping.getBeanConfigurations( constraintHelper, typeResolutionHelper,
valueExtractorManager );
for ( BeanConfiguration beanConfiguration : beanConfigurations ) {
configuredBeans.put( beanConfiguration.getBeanClass().getName(), beanConfiguration );
}
}
return configuredBeans;
}
/**
* Creates a single merged {@code AnnotationProcessingOptions} in case multiple programmatic mappings are provided.
*
* Note that it is made sure at this point that no element (type, property, method etc.) is configured more than once within
* all the given contexts. So the "merge" pulls together the information for all configured elements, but it will never
* merge several configurations for one given element.
*
* @param contexts set of mapping contexts providing annotation processing options to be merged
*
* @return a single annotation processing options object
*/
private static AnnotationProcessingOptions mergeAnnotationProcessingOptions(Set mappings) {
// if we only have one mapping we can return the context of just this mapping
if ( mappings.size() == 1 ) {
return mappings.iterator().next().getAnnotationProcessingOptions();
}
AnnotationProcessingOptions options = new AnnotationProcessingOptionsImpl();
for ( DefaultConstraintMapping mapping : mappings ) {
options.merge( mapping.getAnnotationProcessingOptions() );
}
return options;
}
@Override
@SuppressWarnings("unchecked")
public BeanConfiguration getBeanConfiguration(Class beanClass) {
return (BeanConfiguration) configuredBeans.get( beanClass.getName() );
}
@Override
public AnnotationProcessingOptions getAnnotationProcessingOptions() {
return annotationProcessingOptions;
}
}