Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.hibernate.validator.internal.metadata.provider.ProgrammaticMetaDataProvider Maven / Gradle / Ivy
/*
* JBoss, Home of Professional Open Source
* Copyright 2011, Red Hat, Inc. and/or its affiliates, and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.hibernate.validator.internal.metadata.provider;
import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.validation.ParameterNameProvider;
import org.hibernate.validator.cfg.ConstraintMapping;
import org.hibernate.validator.internal.cfg.DefaultConstraintMapping;
import org.hibernate.validator.internal.cfg.context.ConfiguredConstraint;
import org.hibernate.validator.internal.cfg.context.ConstraintMappingContext;
import org.hibernate.validator.internal.metadata.core.AnnotationProcessingOptions;
import org.hibernate.validator.internal.metadata.core.ConstraintHelper;
import org.hibernate.validator.internal.metadata.core.ConstraintOrigin;
import org.hibernate.validator.internal.metadata.core.MetaConstraint;
import org.hibernate.validator.internal.metadata.descriptor.ConstraintDescriptorImpl;
import org.hibernate.validator.internal.metadata.location.BeanConstraintLocation;
import org.hibernate.validator.internal.metadata.location.ConstraintLocation;
import org.hibernate.validator.internal.metadata.location.ExecutableConstraintLocation;
import org.hibernate.validator.internal.metadata.raw.ConfigurationSource;
import org.hibernate.validator.internal.metadata.raw.ConstrainedElement;
import org.hibernate.validator.internal.metadata.raw.ConstrainedExecutable;
import org.hibernate.validator.internal.metadata.raw.ConstrainedField;
import org.hibernate.validator.internal.metadata.raw.ConstrainedParameter;
import org.hibernate.validator.internal.metadata.raw.ConstrainedType;
import org.hibernate.validator.internal.util.CollectionHelper.Partitioner;
import org.hibernate.validator.internal.util.Contracts;
import org.hibernate.validator.internal.util.ReflectionHelper;
import org.hibernate.validator.internal.util.logging.Log;
import org.hibernate.validator.internal.util.logging.LoggerFactory;
import org.hibernate.validator.spi.group.DefaultGroupSequenceProvider;
import static org.hibernate.validator.internal.util.CollectionHelper.newArrayList;
import static org.hibernate.validator.internal.util.CollectionHelper.newHashSet;
import static org.hibernate.validator.internal.util.CollectionHelper.partition;
/**
* A {@link MetaDataProvider} based on the programmatic constraint API.
*
* @author Gunnar Morling
*/
public class ProgrammaticMetaDataProvider extends MetaDataProviderKeyedByClassName {
private static final Log log = LoggerFactory.make();
private final AnnotationProcessingOptions annotationProcessingOptions;
private final ParameterNameProvider parameterNameProvider;
public ProgrammaticMetaDataProvider(ConstraintHelper constraintHelper,
ParameterNameProvider parameterNameProvider,
Set programmaticMappings) {
super( constraintHelper );
Contracts.assertNotNull( programmaticMappings );
this.parameterNameProvider = parameterNameProvider;
ConstraintMappingContext mergedContext = createMergedMappingContext( programmaticMappings );
initProgrammaticConfiguration( mergedContext );
annotationProcessingOptions = mergedContext.getAnnotationProcessingOptions();
}
@Override
public AnnotationProcessingOptions getAnnotationProcessingOptions() {
return annotationProcessingOptions;
}
/**
* Reads the configuration from {@code context} and creates the appropriate meta-data structures.
*
* @param context the pre-processed configuration information
*/
private void initProgrammaticConfiguration(ConstraintMappingContext context) {
for ( Class clazz : context.getConfiguredClasses() ) {
initClass( clazz, context );
}
}
private void initClass(Class clazz, ConstraintMappingContext context) {
Set constrainedElements =
retrievePropertyMetaData(
context.getConstraintConfig().get( clazz ),
context.getCascadeConfig().get( clazz )
);
Set methodMetaData =
retrieveMethodMetaData(
context.getMethodCascadeConfig().get( clazz ),
context.getMethodConstraintConfig().get( clazz )
);
constrainedElements.addAll( methodMetaData );
DefaultGroupSequenceProvider sequenceProvider = getDefaultGroupSequenceProvider( clazz, context );
addBeanConfiguration(
clazz,
createBeanConfiguration(
ConfigurationSource.API,
clazz,
constrainedElements,
context.getDefaultSequence( clazz ),
sequenceProvider
)
);
}
private DefaultGroupSequenceProvider getDefaultGroupSequenceProvider(Class beanType, ConstraintMappingContext context) {
Class> providerClass = context.getDefaultGroupSequenceProvider(
beanType
);
//retrieve provider from new annotation
if ( providerClass != null ) {
return ReflectionHelper.newInstance( providerClass, "default group sequence provider" );
}
return null;
}
private Set retrievePropertyMetaData(
Set> constraints,
Set cascades) {
Map>> constraintsByLocation = partition(
constraints,
constraintsByLocation()
);
if ( cascades == null ) {
cascades = Collections.emptySet();
}
Set allConfiguredProperties = new HashSet( cascades );
allConfiguredProperties.addAll( constraintsByLocation.keySet() );
Set allPropertyMetaData = newHashSet();
for ( BeanConstraintLocation oneConfiguredProperty : allConfiguredProperties ) {
if ( oneConfiguredProperty.getElementType() == ElementType.FIELD ) {
allPropertyMetaData.add(
new ConstrainedField(
ConfigurationSource.API,
oneConfiguredProperty,
asMetaConstraints( constraintsByLocation.get( oneConfiguredProperty ) ),
Collections., Class>emptyMap(),
cascades.contains( oneConfiguredProperty )
)
);
}
else {
allPropertyMetaData.add(
new ConstrainedType(
ConfigurationSource.API,
oneConfiguredProperty,
asMetaConstraints( constraintsByLocation.get( oneConfiguredProperty ) )
)
);
}
}
return allPropertyMetaData;
}
private Set retrieveMethodMetaData(Set methodCascades,
Set> methodConstraints) {
Map> cascadesByMethod = partition(
methodCascades, cascadesByMethod()
);
Map>> constraintsByMethod = partition(
methodConstraints, constraintsByMethod()
);
Set allConfiguredMethods = new HashSet( cascadesByMethod.keySet() );
allConfiguredMethods.addAll( constraintsByMethod.keySet() );
Set allMethodMetaData = newHashSet();
for ( Method method : allConfiguredMethods ) {
List parameterNames = parameterNameProvider.getParameterNames( method );
Map> cascadesByParameter = partition(
cascadesByMethod.get(
method
), cascadesByParameterIndex()
);
Map>> constraintsByParameter = partition(
constraintsByMethod.get( method ), constraintsByParameterIndex()
);
List parameterMetaDataList = newArrayList();
for ( int i = 0; i < method.getParameterTypes().length; i++ ) {
parameterMetaDataList.add(
new ConstrainedParameter(
ConfigurationSource.API,
new ExecutableConstraintLocation( method, i ),
parameterNames.get( i ),
asMetaConstraints( constraintsByParameter.get( i ) ),
Collections., Class>emptyMap(),
cascadesByParameter.containsKey( i )
)
);
}
ConstrainedExecutable methodMetaData = new ConstrainedExecutable(
ConfigurationSource.API,
new ExecutableConstraintLocation( method ),
parameterMetaDataList,
Collections.>emptySet(),
asMetaConstraints( constraintsByParameter.get( null ) ),
Collections., Class>emptyMap(),
cascadesByParameter.containsKey( null )
);
allMethodMetaData.add( methodMetaData );
}
return allMethodMetaData;
}
private Set> asMetaConstraints(Set> constraints) {
if ( constraints == null ) {
return Collections.emptySet();
}
Set> theValue = newHashSet();
for ( ConfiguredConstraint oneConfiguredConstraint : constraints ) {
theValue.add( asMetaConstraint( oneConfiguredConstraint ) );
}
return theValue;
}
private MetaConstraint asMetaConstraint(ConfiguredConstraint config) {
ConstraintDescriptorImpl constraintDescriptor = new ConstraintDescriptorImpl (
config.getLocation().getMember(),
config.createAnnotationProxy(),
constraintHelper,
config.getLocation().getElementType(),
ConstraintOrigin.DEFINED_LOCALLY
);
return new MetaConstraint ( constraintDescriptor, config.getLocation() );
}
private Partitioner cascadesByMethod() {
return new Partitioner() {
@Override
public Method getPartition(ExecutableConstraintLocation location) {
return (Method) location.getMember();
}
};
}
private Partitioner cascadesByParameterIndex() {
return new Partitioner() {
@Override
public Integer getPartition(ExecutableConstraintLocation location) {
return location.getParameterIndex();
}
};
}
private Partitioner> constraintsByMethod() {
return new Partitioner>() {
@Override
public Method getPartition(ConfiguredConstraint constraint) {
return (Method) constraint.getLocation().getMember();
}
};
}
private Partitioner> constraintsByParameterIndex() {
return new Partitioner>() {
@Override
public Integer getPartition(
ConfiguredConstraint v) {
return v.getLocation().getParameterIndex();
}
};
}
/**
* Creates a single merged {@code ConstraintMappingContext} in case multiple programmatic mappings are provided.
*
* @param programmaticMappings set of constraint mappings to merge into a single context
*
* @return a single merged constraint context
*/
private ConstraintMappingContext createMergedMappingContext(Set programmaticMappings) {
// if we only have one mapping we can return the context of just this mapping
if ( programmaticMappings.size() == 1 ) {
return ( (DefaultConstraintMapping) programmaticMappings.iterator().next() ).getContext();
}
ConstraintMappingContext mergedContext = new ConstraintMappingContext();
for ( ConstraintMapping mapping : programmaticMappings ) {
ConstraintMappingContext context = ( (DefaultConstraintMapping) mapping ).getContext();
mergedContext.getAnnotationProcessingOptions().merge( context.getAnnotationProcessingOptions() );
for ( Set> propertyConstraints : context.getConstraintConfig()
.values() ) {
for ( ConfiguredConstraint constraint : propertyConstraints ) {
mergedContext.addConstraintConfig( constraint );
}
}
for ( Set beanConstraintLocations : context.getCascadeConfig().values() ) {
for ( BeanConstraintLocation beanLocation : beanConstraintLocations ) {
mergedContext.addCascadeConfig( beanLocation );
}
}
for ( Set> methodConstraints : context.getMethodConstraintConfig()
.values() ) {
for ( ConfiguredConstraint methodConstraint : methodConstraints ) {
mergedContext.addMethodConstraintConfig( methodConstraint );
}
}
for ( Set cascadedMethodConstraints : context.getMethodCascadeConfig()
.values() ) {
for ( ExecutableConstraintLocation methodCascade : cascadedMethodConstraints ) {
mergedContext.addMethodCascadeConfig( methodCascade );
}
}
mergeGroupSequenceAndGroupSequenceProvider( mergedContext, context );
}
return mergedContext;
}
private void mergeGroupSequenceAndGroupSequenceProvider(ConstraintMappingContext mergedContext, ConstraintMappingContext context) {
for ( Class clazz : context.getConfiguredClasses() ) {
mergeSequenceAndProviderForClass( mergedContext, context, clazz );
}
}
private void mergeSequenceAndProviderForClass(ConstraintMappingContext mergedContext, ConstraintMappingContext context, Class clazz) {
if ( context.getDefaultGroupSequenceProvider( clazz ) != null ) {
if ( mergedContext.getDefaultGroupSequenceProvider( clazz ) != null ) {
throw log.getMultipleDefinitionOfDefaultGroupSequenceProviderException();
}
mergedContext.addDefaultGroupSequenceProvider(
clazz,
context.getDefaultGroupSequenceProvider( clazz )
);
}
if ( context.getDefaultSequence( clazz ) != null ) {
if ( mergedContext.getDefaultSequence( clazz ) != null ) {
throw log.getMultipleDefinitionOfDefaultGroupSequenceException();
}
mergedContext.addDefaultGroupSequence(
clazz,
context.getDefaultSequence( clazz )
);
}
}
private Partitioner> constraintsByLocation() {
return new Partitioner>() {
@Override
public BeanConstraintLocation getPartition(ConfiguredConstraint constraint) {
return constraint.getLocation();
}
};
}
}