Spring validation参数校验系列
2、Spring validation参数校验之自定义校验规则及编程式校验等进阶篇
3、【源码】Spring validation参数校验原理解析之Controller控制器参数校验中@RequestBody参数校验实现原理
4、【源码】Spring validation参数校验原理解析之Controller控制器参数校验中@ModelAttribute及实体类参数校验实现原理
5、【源码】Spring validation参数校验原理解析之基本类型参数及Service层方法参数校验实现原理
6、【源码】Spring validation校验的核心类ValidatorImpl、MetaDataProvider和AnnotationMetaDataProvider源码分析
7、Spring validation参数校验高级篇之跨参数校验Cross-Parameter及分组序列校验@GroupSequenceProvider、@GroupSequence
8、【源码】Spring validation参数校验之跨参数校验Cross-Parameter原理分析
9、【源码】Spring validation参数校验之分组序列校验@GroupSequenceProvider、@GroupSequence的实现原理
10、【源码】Spring validation参数校验实现原理总结
前言
限于篇幅,在前面的三篇讲解源码的文章中,对于一些类只做了简单的说明,这一篇专门用来讲解源码中比较关键的几个类。
温馨提醒:
Hibernate validation的设计比较复杂,要一次性全部分析清楚很困难,关联的细节很多。所以《Spring validation参数校验系列》文章通过从整体到细节,在每一篇中,不影响主题内容的情况下,穿插引入一些细节。在分享中,也会暂时忽略一些细节,留在下一篇讲解。建议如果本篇不太理解的,可以看看该系列的上一篇或者下一篇源码讲解文章。
ValidatorImpl
ValidatorImpl是Hibernate validation参数校验Validator接口的唯一实现。类的方法在前面的三篇Spring validation实现原理文章中有陆续分析到。这里从宏观的角度来看一下这个类。
ValidatorImpl.java
package org.hibernate.validator.internal.engine;
/**
* 该类实现了Validator和ExecutableValidator接口
*/
public class ValidatorImpl implements Validator, ExecutableValidator {
}
该类实现了Validator和ExecutableValidator接口。
Validator.java
package javax.validation;
public interface Validator {
/**
* 验证object中添加中的所有约束。校验失败,返回约束集合,成功返回空集合
*/
<T> Set<ConstraintViolation<T>> validate(T object, Class<?>... groups);
/**
* 验证object对象中的propertyName属性的所有约束。校验失败,返回约束集合,成功返回空集合
*/
<T> Set<ConstraintViolation<T>> validateProperty(T object,
String propertyName,
Class<?>... groups);
/**
* 验证beanType中的propertyName属性的value值是否满足所有施加的约束
*/
<T> Set<ConstraintViolation<T>> validateValue(Class<T> beanType,
String propertyName,
Object value,
Class<?>... groups);
/**
* 返回描述clazz约束的描述符对象。返回的对象(以及包括{@link ConstraintDescriptor}s在内的关联对象)是不可变的。
*/
BeanDescriptor getConstraintsForClass(Class<?> clazz);
/**
* 返回指定类型的实例,该实例允许访问特定于提供程序的API。
*/
<T> T unwrap(Class<T> type);
/**
* 返回用于验证约定方法或构造方法的参数及返回值信息。
*/
ExecutableValidator forExecutables();
}
ExecutableValidator.java
package javax.validation.executable;
/**
* 用于验证方法或构造函数的参数和返回值
*/
public interface ExecutableValidator {
/**
* 验证对给定方法的参数施加的所有约束
*
* @param <T> 要验证的方法所在的类类型
* @param object 要验证的方法的类对象
* @param method 验证参数约束的方法
* @param parameterValues 方法中的参数值
* @param groups 校验的分组。默认为Default
* @return 如果校验失败,返回失败集合;校验成功,返回空集合
* @throws IllegalArgumentException 如果传递的参数有问题,抛IllegalArgumentException异常
* @throws ValidationException 如果在验证过程中发生不可恢复的错误,抛ValidationException异常
*/
<T> Set<ConstraintViolation<T>> validateParameters(T object,
Method method,
Object[] parameterValues,
Class<?>... groups);
/**
* 验证给定方法的返回值施加的所有约束。其他说明同上
*/
<T> Set<ConstraintViolation<T>> validateReturnValue(T object,
Method method,
Object returnValue,
Class<?>... groups);
/**
* 验证构造方法的参数施加的所有约束
*/
<T> Set<ConstraintViolation<T>> validateConstructorParameters(Constructor<? extends T> constructor,
Object[] parameterValues,
Class<?>... groups);
/**
* 验证构造方法的返回值施加的所有约束
*/
<T> Set<ConstraintViolation<T>> validateConstructorReturnValue(Constructor<? extends T> constructor,
T createdObject, Class<?>... groups);
}
ValidatorImpl对外提供的方法为这两个接口的方法。即ValidatorImpl提供了属性校验、方法参数及返回值校验、构造方法参数校验。在前面的三篇源码中有介绍了部分实现。
MetaDataProvider
MetaDataProvider返回一个类中配置的约束、组序列等相关的配置信息。
MetaDataProvider.java
package org.hibernate.validator.internal.metadata.provider;
import org.hibernate.validator.internal.metadata.core.AnnotationProcessingOptions;
import org.hibernate.validator.internal.metadata.raw.BeanConfiguration;
/**
* 提供与约束相关的元数据,如约束、默认组序列等。
* 实现基于不同的元数据源,如XML、编程映射和注释(BeanConfiguration枚举中定义)。
* 元数据提供程序只返回直接为一个类配置的元数据,它们不处理合并超类或实现接口的元数据。
*/
public interface MetaDataProvider {
/**
* 返回此提供程序配置的注释处理选项。
* AnnotationProcessingOptionsImpl为AnnotationProcessingOptions的唯一实现类,提供了xxxIgnoredFor()方法的接口
* (如:areClassLevelConstraintsIgnoredFor()、areParameterConstraintsIgnoredFor()等),用于配置哪些是不需要校验的
*/
AnnotationProcessingOptions getAnnotationProcessingOptions();
/**
* 返回给定类型的bean配置,如果此提供程序没有给定类型的元数据,则返回null。
* BeanConfiguration用于存储来源于一个ConfigurationSource的一个Java类型的完整约束相关配置。
* 包含约束(字段、方法和类级别)上的元数据以及默认组序列上的元数据。
*/
<T> BeanConfiguration<? super T> getBeanConfiguration(Class<T> beanClass);
}
一个bean类的约束元数据信息都记录在BeanConfiguration中。
BeanConfiguration.java
package org.hibernate.validator.internal.metadata.raw;
import java.util.List;
import java.util.Set;
import org.hibernate.validator.internal.util.CollectionHelper;
import org.hibernate.validator.spi.group.DefaultGroupSequenceProvider;
/**
* 表示源自一个ConfigurationSource的一个Java类型的完整约束相关配置。包含约束(字段、方法和类级别)上的元数据以及默认组序列上的元数据。
*/
public class BeanConfiguration<T> {
// 枚举类。指定配置方式。有XML、Annotation、API,针对不同的配置方法,获取约束信息时,需要使用不同的方法
// 例如Annotation方式,则通过读取注解信息;如果是XML,则需要解析XML标签
private final ConfigurationSource source;
// 对应的bean类
private final Class<T> beanClass;
// 校验的元素。有四个子类:
// ConstrainedField/ConstrainedType/ConstrainedParameter/ConstrainedExecutable,分别对应属性、类、参数及方法
private final Set<ConstrainedElement> constrainedElements;
// 分组序列
private final List<Class<?>> defaultGroupSequence;
// 动态分组序列的约定程序
private final DefaultGroupSequenceProvider<? super T> defaultGroupSequenceProvider;
// BeanConfiguration只有上面这些属性,其他代码为对应属性的getter/setter及构造方法,此处省略
}
BeanConfiguration中记录了某个bean的属性、类、参数、方法添加的约束信息、配置来源、分组序列以及动态分组序列程序。
通过动态分组序列程序,可以根据不同的条件,修改某个约束使用哪个分组进行判断。例如积分维护,积分增加是消费、参加活动、购买等方式获得,积分减少是抵扣、过期等方式扣减,针对积分是增还是减,传入的类型是不同的。此时可以定义类型在增加和减少的枚举中为不同的组,然后自定义DefaultGroupSequenceProvider,在DefaultGroupSequenceProvider的getValidationGroups()方法中,根据是增加还是减少,返回不同的组。
ConfigurationSource.java
package org.hibernate.validator.internal.metadata.raw;
/**
* 约束元数据信息的来源
*/
public enum ConfigurationSource {
// 注解配置
ANNOTATION( 0 ),
// XML配置
XML( 1 ),
// 程序API配置
API( 2 );
}
ConfigurationSource有三种来源,对应的MetaDataProvider有三个实现类,分别为:AnnotationMetaDataProvider、ProgrammaticMetaDataProvider、XmlMetaDataProvider,分别处理ConfigurationSource中的三种来源。在Spring及SpringBoot中,更多都是通过Annotation注解的方式实现。
AnnotationMetaDataProvider
AnnotationMetaDataProvider实现了MetaDataProvider接口,用于解析bean类中采用Annotation注解方式添加的约束元信息。
AnnotationMetaDataProvider.java
/*
* 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.metadata.provider;
import org.hibernate.validator.group.GroupSequenceProvider;
import org.hibernate.validator.internal.engine.ConstraintCreationContext;
import org.hibernate.validator.internal.engine.valueextraction.ArrayElement;
import org.hibernate.validator.internal.metadata.aggregated.CascadingMetaDataBuilder;
import org.hibernate.validator.internal.metadata.core.*;
import org.hibernate.validator.internal.metadata.descriptor.ConstraintDescriptorImpl;
import org.hibernate.validator.internal.metadata.descriptor.ConstraintDescriptorImpl.ConstraintType;
import org.hibernate.validator.internal.metadata.location.ConstraintLocation;
import org.hibernate.validator.internal.metadata.location.ConstraintLocation.ConstraintLocationKind;
import org.hibernate.validator.internal.metadata.raw.*;
import org.hibernate.validator.internal.properties.Callable;
import org.hibernate.validator.internal.properties.Constrainable;
import org.hibernate.validator.internal.properties.Getter;
import org.hibernate.validator.internal.properties.javabean.*;
import org.hibernate.validator.internal.util.CollectionHelper;
import org.hibernate.validator.internal.util.ReflectionHelper;
import org.hibernate.validator.internal.util.annotation.ConstraintAnnotationDescriptor;
import org.hibernate.validator.internal.util.logging.Log;
import org.hibernate.validator.internal.util.logging.LoggerFactory;
import org.hibernate.validator.internal.util.privilegedactions.*;
import org.hibernate.validator.spi.group.DefaultGroupSequenceProvider;
import javax.validation.GroupSequence;
import javax.validation.Valid;
import javax.validation.groups.ConvertGroup;
import java.lang.annotation.Annotation;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.*;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.*;
import java.util.stream.Collectors;
import static org.hibernate.validator.internal.util.CollectionHelper.*;
import static org.hibernate.validator.internal.util.logging.Messages.MESSAGES;
public class AnnotationMetaDataProvider implements MetaDataProvider {
private static final Log LOG = LoggerFactory.make( MethodHandles.lookup() );
private final ConstraintCreationContext constraintCreationContext;
private final AnnotationProcessingOptions annotationProcessingOptions;
private final JavaBeanHelper javaBeanHelper;
// BeanConfiguration中记录了某个bean的属性、类、参数、方法添加的约束信息、配置来源、分组序列以及动态分组序列程序
private final BeanConfiguration<Object> objectBeanConfiguration;
public AnnotationMetaDataProvider(ConstraintCreationContext constraintCreationContext,
JavaBeanHelper javaBeanHelper,
AnnotationProcessingOptions annotationProcessingOptions) {
this.constraintCreationContext = constraintCreationContext;
this.javaBeanHelper = javaBeanHelper;
this.annotationProcessingOptions = annotationProcessingOptions;
this.objectBeanConfiguration = retrieveBeanConfiguration( Object.class );
}
/**
* 返回一个AnnotationProcessingOptionsImpl对象,记录哪些类、方法、参数是不需要校验的
*/
@Override
public AnnotationProcessingOptions getAnnotationProcessingOptions() {
return new AnnotationProcessingOptionsImpl();
}
/**
* 获取bean类中定义的属性、类、参数、方法添加的约束信息、配置来源、分组序列以及动态分组序列程序
*/
@Override
@SuppressWarnings("unchecked")
public <T> BeanConfiguration<T> getBeanConfiguration(Class<T> beanClass) {
if ( Object.class.equals( beanClass ) ) {
return (BeanConfiguration<T>) objectBeanConfiguration;
}
return retrieveBeanConfiguration( beanClass );
}
/**
* 检索bean类的元数据信息
* @param beanClass The bean class for which to retrieve the meta data
*
* @return Retrieves constraint related meta data from the annotations of the given type.
*/
private <T> BeanConfiguration<T> retrieveBeanConfiguration(Class<T> beanClass) {
// 获取类中定义的属性添加的约束元素信息
Set<ConstrainedElement> constrainedElements = getFieldMetaData( beanClass );
// 获取类中定义的方法添加的约束元素信息
constrainedElements.addAll( getMethodMetaData( beanClass ) );
// 获取类的构造方法添加的约束元素信息
constrainedElements.addAll( getConstructorMetaData( beanClass ) );
// 获取类级添加的约束信息
Set<MetaConstraint<?>> classLevelConstraints = getClassLevelConstraints( beanClass );
if ( !classLevelConstraints.isEmpty() ) {
ConstrainedType classLevelMetaData =
new ConstrainedType(
ConfigurationSource.ANNOTATION,
beanClass,
classLevelConstraints
);
constrainedElements.add( classLevelMetaData );
}
// 封装成BeanConfiguration对象,来源为Annotation
return new BeanConfiguration<>(
ConfigurationSource.ANNOTATION,
beanClass,
constrainedElements,
getDefaultGroupSequence( beanClass ),
getDefaultGroupSequenceProvider( beanClass )
);
}
/**
* 获取bean中添加的@GroupSequence注解的组序列。组序列中的组顺序执行,排前面的组对应的注解约束会先判断,如果前面的失败了,不会校验排后面的组
* @param beanClass
* @return
*/
private List<Class<?>> getDefaultGroupSequence(Class<?> beanClass) {
GroupSequence groupSequenceAnnotation = beanClass.getAnnotation( GroupSequence.class );
return groupSequenceAnnotation != null ? Arrays.asList( groupSequenceAnnotation.value() ) : null;
}
/**
* 获取类中定义的动态分组的约定程序
* @param beanClass
* @param <T>
* @return
*/
private <T> DefaultGroupSequenceProvider<? super T> getDefaultGroupSequenceProvider(Class<T> beanClass) {
// 判断对应的bean是否添加了GroupSequenceProvider注解
GroupSequenceProvider groupSequenceProviderAnnotation = beanClass.getAnnotation( GroupSequenceProvider.class );
// 只有添加了GroupSequenceProvider注解才会返回动态分组的约定程序
if ( groupSequenceProviderAnnotation != null ) {
// 获取GroupSequenceProvider注解中指定的约定程序类,该类实现了DefaultGroupSequenceProvider接口
@SuppressWarnings("unchecked")
Class<? extends DefaultGroupSequenceProvider<? super T>> providerClass =
(Class<? extends DefaultGroupSequenceProvider<? super T>>) groupSequenceProviderAnnotation.value();
// 创建一个自定义的DefaultGroupSequenceProvider实例
return newGroupSequenceProviderClassInstance( beanClass, providerClass );
}
return null;
}
/**
* 创建一个DefaultGroupSequenceProvider实例,getValidationGroups()方法的参数必现是beanClass类型
* @param beanClass
* @param providerClass
* @param <T>
* @return
*/
private <T> DefaultGroupSequenceProvider<? super T> newGroupSequenceProviderClassInstance(Class<T> beanClass,
Class<? extends DefaultGroupSequenceProvider<? super T>> providerClass) {
Method[] providerMethods = run( GetMethods.action( providerClass ) );
for ( Method method : providerMethods ) {
Class<?>[] paramTypes = method.getParameterTypes();
// 判断DefaultGroupSequenceProvider接口的getValidationGroups()方法的参数是否为beanClass类型
if ( "getValidationGroups".equals( method.getName() ) && !method.isBridge()
&& paramTypes.length == 1 && paramTypes[0].isAssignableFrom( beanClass ) ) {
return run(
NewInstance.action( providerClass, "the default group sequence provider" )
);
}
}
throw LOG.getWrongDefaultGroupSequenceProviderTypeException( beanClass );
}
/**
* 获取类级添加的约束信息
* @param clazz
* @return
*/
private Set<MetaConstraint<?>> getClassLevelConstraints(Class<?> clazz) {
if ( annotationProcessingOptions.areClassLevelConstraintsIgnoredFor( clazz ) ) {
return Collections.emptySet();
}
// 获取类级定义的约束信息
List<ConstraintDescriptorImpl<?>> classLevelConstraintDescriptors = findConstraints( null, clazz.getDeclaredAnnotations(),
ConstraintLocationKind.TYPE );
if ( classLevelConstraintDescriptors.isEmpty() ) {
return Collections.emptySet();
}
Set<MetaConstraint<?>> classLevelConstraints = newHashSet( classLevelConstraintDescriptors.size() );
ConstraintLocation location = ConstraintLocation.forClass( clazz );
// 封装为MetaConstraints对象
for ( ConstraintDescriptorImpl<?> constraintDescriptor : classLevelConstraintDescriptors ) {
classLevelConstraints.add( MetaConstraints.create( constraintCreationContext.getTypeResolutionHelper(),
constraintCreationContext.getValueExtractorManager(),
constraintCreationContext.getConstraintValidatorManager(),
constraintDescriptor,
location ) );
}
return classLevelConstraints;
}
/**
* 获取bean类中定义的属性添加的约束元数据
* @param beanClass
* @return
*/
private Set<ConstrainedElement> getFieldMetaData(Class<?> beanClass) {
Set<ConstrainedElement> propertyMetaData = newHashSet();
// 遍历类中的属性
for ( Field field : run( GetDeclaredFields.action( beanClass ) ) ) {
// HV-172
if ( Modifier.isStatic( field.getModifiers() ) || field.isSynthetic() ) {
continue;
}
JavaBeanField javaBeanField = javaBeanHelper.field( field );
if ( annotationProcessingOptions.areMemberConstraintsIgnoredFor( javaBeanField ) ) {
continue;
}
// 调用findPropertyMetaData()获取属性中添加的约束元数据
propertyMetaData.add( findPropertyMetaData( javaBeanField ) );
}
return propertyMetaData;
}
/**
* 查找类属性的约束元数据,封装成ConstrainedField对象并返回
* @param javaBeanField
* @return
*/
private ConstrainedField findPropertyMetaData(JavaBeanField javaBeanField) {
// 查找给定属性添加的Validator相关的约束信息,并封装成MetaConstraint集合
Set<MetaConstraint<?>> constraints = convertToMetaConstraints(
findConstraints( javaBeanField, ConstraintLocationKind.FIELD ),
javaBeanField
);
// 找级联元数据。通过判断添加注解的元素是否有添加@Valid,如果有为级联,返回的CascadingMetaDataBuilder的cascading为true
CascadingMetaDataBuilder cascadingMetaDataBuilder = findCascadingMetaData( javaBeanField );
Set<MetaConstraint<?>> typeArgumentsConstraints = findTypeAnnotationConstraints( javaBeanField );
return new ConstrainedField(
ConfigurationSource.ANNOTATION,
javaBeanField,
constraints,
typeArgumentsConstraints,
cascadingMetaDataBuilder
);
}
/**
* 将ConstraintDescriptorImpl集合对象转换为MetaConstraint集合
* @param constraintDescriptors
* @param javaBeanField
* @return
*/
private Set<MetaConstraint<?>> convertToMetaConstraints(List<ConstraintDescriptorImpl<?>> constraintDescriptors, JavaBeanField javaBeanField) {
if ( constraintDescriptors.isEmpty() ) {
return Collections.emptySet();
}
Set<MetaConstraint<?>> constraints = newHashSet( constraintDescriptors.size() );
ConstraintLocation location = ConstraintLocation.forField( javaBeanField );
for ( ConstraintDescriptorImpl<?> constraintDescription : constraintDescriptors ) {
constraints.add( MetaConstraints.create( constraintCreationContext.getTypeResolutionHelper(),
constraintCreationContext.getValueExtractorManager(),
constraintCreationContext.getConstraintValidatorManager(),
constraintDescription, location ) );
}
return constraints;
}
private Set<ConstrainedExecutable> getConstructorMetaData(Class<?> clazz) {
Executable[] declaredConstructors = run( GetDeclaredConstructors.action( clazz ) );
return getMetaData( declaredConstructors );
}
/**
* 获取clazz定义的所有方法,调用getMetaData(),遍历所有方法,解析方法中添加的约束
* @param clazz
* @return
*/
private Set<ConstrainedExecutable> getMethodMetaData(Class<?> clazz) {
Executable[] declaredMethods = run( GetDeclaredMethods.action( clazz ) );
return getMetaData( declaredMethods );
}
/**
* 遍历方法,获取约束信息
* @param executableElements
* @return
*/
private Set<ConstrainedExecutable> getMetaData(Executable[] executableElements) {
Set<ConstrainedExecutable> executableMetaData = newHashSet();
for ( Executable executable : executableElements ) {
// HV-172; ignoring synthetic methods (inserted by the compiler), as they can't have any constraints
// anyway and possibly hide the actual method with the same signature in the built meta model
if ( Modifier.isStatic( executable.getModifiers() ) || executable.isSynthetic() ) {
continue;
}
executableMetaData.add( findExecutableMetaData( executable ) );
}
return executableMetaData;
}
/**
* 查找给定的方法或构造器中添加的所有约束
* Finds all constraint annotations defined for the given method or constructor.
*
* @param executable The executable element to check for constraints annotations.
*
* @return A meta data object describing the constraints specified for the
* given element.
*/
private ConstrainedExecutable findExecutableMetaData(Executable executable) {
JavaBeanExecutable<?> javaBeanExecutable = javaBeanHelper.executable( executable );
// 获取方法的入参中添加的约束
List<ConstrainedParameter> parameterConstraints = getParameterMetaData( javaBeanExecutable );
// 获取方法添加的约束
Map<ConstraintType, List<ConstraintDescriptorImpl<?>>> executableConstraints = findConstraints(
javaBeanExecutable,
ConstraintLocationKind.of( javaBeanExecutable.getConstrainedElementKind() )
).stream().collect( Collectors.groupingBy( ConstraintDescriptorImpl::getConstraintType ) );
Set<MetaConstraint<?>> crossParameterConstraints;
if ( annotationProcessingOptions.areCrossParameterConstraintsIgnoredFor( javaBeanExecutable ) ) {
crossParameterConstraints = Collections.emptySet();
}
else {
crossParameterConstraints = convertToMetaConstraints(
executableConstraints.get( ConstraintType.CROSS_PARAMETER ),
javaBeanExecutable
);
}
Set<MetaConstraint<?>> returnValueConstraints;
Set<MetaConstraint<?>> typeArgumentsConstraints;
CascadingMetaDataBuilder cascadingMetaDataBuilder;
if ( annotationProcessingOptions.areReturnValueConstraintsIgnoredFor( javaBeanExecutable ) ) {
returnValueConstraints = Collections.emptySet();
typeArgumentsConstraints = Collections.emptySet();
cascadingMetaDataBuilder = CascadingMetaDataBuilder.nonCascading();
}
else {
// 获取方法返回值添加的约束信息
typeArgumentsConstraints = findTypeAnnotationConstraints( javaBeanExecutable );
returnValueConstraints = convertToMetaConstraints(
executableConstraints.get( ConstraintType.GENERIC ),
javaBeanExecutable
);
cascadingMetaDataBuilder = findCascadingMetaData( javaBeanExecutable );
}
// 封装成ConstrainedExecutable对象
return new ConstrainedExecutable(
ConfigurationSource.ANNOTATION,
javaBeanExecutable,
parameterConstraints,
crossParameterConstraints,
returnValueConstraints,
typeArgumentsConstraints,
cascadingMetaDataBuilder
);
}
private Set<MetaConstraint<?>> convertToMetaConstraints(List<ConstraintDescriptorImpl<?>> constraintDescriptors, Callable callable) {
if ( constraintDescriptors == null || constraintDescriptors.isEmpty() ) {
return Collections.emptySet();
}
Set<MetaConstraint<?>> constraints = newHashSet( constraintDescriptors.size() );
ConstraintLocation returnValueLocation = ConstraintLocation.forReturnValue( callable );
ConstraintLocation crossParameterLocation = ConstraintLocation.forCrossParameter( callable );
for ( ConstraintDescriptorImpl<?> constraintDescriptor : constraintDescriptors ) {
ConstraintLocation location = constraintDescriptor.getConstraintType() == ConstraintType.GENERIC
? returnValueLocation
: crossParameterLocation;
constraints.add( MetaConstraints.create( constraintCreationContext.getTypeResolutionHelper(),
constraintCreationContext.getValueExtractorManager(),
constraintCreationContext.getConstraintValidatorManager(), constraintDescriptor, location ) );
}
return constraints;
}
/**
* 检索给定的方法的参数添加的约束注解信息
* Retrieves constraint related meta data for the parameters of the given
* executable.
*
* @param javaBeanExecutable The executable of interest.
*
* @return A list with parameter meta data for the given executable.
*/
private List<ConstrainedParameter> getParameterMetaData(JavaBeanExecutable<?> javaBeanExecutable) {
if ( !javaBeanExecutable.hasParameters() ) {
return Collections.emptyList();
}
List<JavaBeanParameter> parameters = javaBeanExecutable.getParameters();
List<ConstrainedParameter> metaData = new ArrayList<>( parameters.size() );
int i = 0;
// 遍历每个参数
for ( JavaBeanParameter parameter : parameters ) {
// 判断该参数是否无需考虑约束条件的类型
if ( annotationProcessingOptions.areParameterConstraintsIgnoredFor( javaBeanExecutable, i ) ) {
metaData.add(
new ConstrainedParameter(
ConfigurationSource.ANNOTATION,
javaBeanExecutable,
parameter.getGenericType(),
i,
Collections.emptySet(),
Collections.emptySet(),
CascadingMetaDataBuilder.nonCascading()
)
);
i++;
continue;
}
// 查找方法参数添加的所有约束注释,并在约束描述符列表中返回它们。
List<ConstraintDescriptorImpl<?>> constraintDescriptors = findConstraints( javaBeanExecutable, parameter, ConstraintLocationKind.PARAMETER );
Set<MetaConstraint<?>> parameterConstraints;
if ( !constraintDescriptors.isEmpty() ) {
parameterConstraints = newHashSet( constraintDescriptors.size() );
ConstraintLocation location = ConstraintLocation.forParameter( javaBeanExecutable, i );
// 遍历添加的约束,封装成MetaConstraints对象
for ( ConstraintDescriptorImpl<?> constraintDescriptorImpl : constraintDescriptors ) {
parameterConstraints.add(
MetaConstraints.create( constraintCreationContext.getTypeResolutionHelper(),
constraintCreationContext.getValueExtractorManager(),
constraintCreationContext.getConstraintValidatorManager(), constraintDescriptorImpl,
location ) );
}
}
else {
parameterConstraints = Collections.emptySet();
}
Set<MetaConstraint<?>> typeArgumentsConstraints = findTypeAnnotationConstraintsForExecutableParameter( javaBeanExecutable, parameter );
// 通过判断添加注解的元素是否有添加@Valid,如果有为级联,返回的CascadingMetaDataBuilder的cascading为true
CascadingMetaDataBuilder cascadingMetaData = findCascadingMetaData( parameter );
// 将信息封装成ConstrainedParameter对象
metaData.add(
new ConstrainedParameter(
ConfigurationSource.ANNOTATION,
javaBeanExecutable,
parameter.getGenericType(),
i,
parameterConstraints,
typeArgumentsConstraints,
cascadingMetaData
)
);
i++;
}
return metaData;
}
/**
* 查找为给定可约束项定义的所有约束注释,并在约束描述符列表中返回它们。
*/
private List<ConstraintDescriptorImpl<?>> findConstraints(JavaBeanAnnotatedConstrainable constrainable, ConstraintLocationKind kind) {
return findConstraints( constrainable, constrainable, kind );
}
/**
* 查找为给定可约束项定义的所有约束注释,并在约束描述符列表中返回它们。
*/
private List<ConstraintDescriptorImpl<?>> findConstraints(Constrainable constrainable, JavaBeanAnnotatedElement annotatedElement,
ConstraintLocationKind kind) {
List<ConstraintDescriptorImpl<?>> metaData = newArrayList();
// 获取元素添加的所有注解,遍历
for ( Annotation annotation : annotatedElement.getDeclaredAnnotations() ) {
// 调用findConstraintAnnotations()方法,查找约束性注解信息,并返回
metaData.addAll( findConstraintAnnotations( constrainable, annotation, kind ) );
}
return metaData;
}
/**
* 查找为给定可约束项定义的所有约束注释,并在约束描述符列表中返回它们。
*/
private List<ConstraintDescriptorImpl<?>> findConstraints(Constrainable constrainable, Annotation[] annotations,
ConstraintLocationKind kind) {
if ( annotations.length == 0 ) {
return Collections.emptyList();
}
List<ConstraintDescriptorImpl<?>> metaData = newArrayList();
for ( Annotation annotation : annotations ) {
metaData.addAll( findConstraintAnnotations( constrainable, annotation, kind ) );
}
return metaData;
}
/**
* 检查给定的注释,看看它是单值约束注释还是多值约束注释
*/
protected <A extends Annotation> List<ConstraintDescriptorImpl<?>> findConstraintAnnotations(
Constrainable constrainable,
A annotation,
ConstraintLocationKind type) {
// HV-1049 and HV-1311 - Ignore annotations from the JDK (jdk.internal.* and java.*); They cannot be constraint
// annotations so skip them right here, as for the proper check we'd need package access permission for
// "jdk.internal" and "java".
/**
* HV-1049和HV-1311-忽略JDK(JDK.internal.和java.)中的注释;它们不能是约束注释,所以请跳过它们,因为为了进行正确的检查,
* 需要“jdk.internal”和“java”的包访问权限。
*/
if ( constraintCreationContext.getConstraintHelper().isJdkAnnotation( annotation.annotationType() ) ) {
return Collections.emptyList();
}
List<Annotation> constraints = newArrayList();
Class<? extends Annotation> annotationType = annotation.annotationType();
/**
* ConstraintHelper.isConstraintAnnotation()【执行constraintCreationContext.getConstraintHelper().
* isConstraintAnnotation( annotationType )】 -> isBuiltinConstraint() -> BuiltinConstraint.isBuiltin()
* 【BuiltinConstraint为枚举类,列举了validation的所有约束字段。从而判断当前的参数是否添加了约束】
*/
if ( constraintCreationContext.getConstraintHelper().isConstraintAnnotation( annotationType ) ) {
constraints.add( annotation );
}
// 暂时没有用到。用于判断多值约束
else if ( constraintCreationContext.getConstraintHelper().isMultiValueConstraint( annotationType ) ) {
constraints.addAll( constraintCreationContext.getConstraintHelper().getConstraintsFromMultiValueConstraint( annotation ) );
}
return constraints.stream()
.map( c -> buildConstraintDescriptor( constrainable, c, type ) )
.collect( Collectors.toList() );
}
private Map<Class<?>, Class<?>> getGroupConversions(AnnotatedType annotatedType) {
return getGroupConversions(
annotatedType.getAnnotation( ConvertGroup.class ),
annotatedType.getAnnotation( ConvertGroup.List.class )
);
}
private Map<Class<?>, Class<?>> getGroupConversions(ConvertGroup groupConversion, ConvertGroup.List groupConversionList) {
if ( groupConversion == null && ( groupConversionList == null || groupConversionList.value().length == 0 ) ) {
return Collections.emptyMap();
}
Map<Class<?>, Class<?>> groupConversions = newHashMap();
if ( groupConversion != null ) {
groupConversions.put( groupConversion.from(), groupConversion.to() );
}
if ( groupConversionList != null ) {
for ( ConvertGroup conversion : groupConversionList.value() ) {
if ( groupConversions.containsKey( conversion.from() ) ) {
throw LOG.getMultipleGroupConversionsForSameSourceException(
conversion.from(),
CollectionHelper.<Class<?>>asSet(
groupConversions.get( conversion.from() ),
conversion.to()
)
);
}
groupConversions.put( conversion.from(), conversion.to() );
}
}
return groupConversions;
}
private <A extends Annotation> ConstraintDescriptorImpl<A> buildConstraintDescriptor(Constrainable constrainable,
A annotation,
ConstraintLocationKind type) {
return new ConstraintDescriptorImpl<>(
constraintCreationContext.getConstraintHelper(),
constrainable,
new ConstraintAnnotationDescriptor<>( annotation ),
type
);
}
/**
* 运行给定的特权操作,必要时使用特权块
*/
private <T> T run(PrivilegedAction<T> action) {
return System.getSecurityManager() != null ? AccessController.doPrivileged( action ) : action.run();
}
/**
* 查找字段的类型参数约束
*/
protected Set<MetaConstraint<?>> findTypeAnnotationConstraints(JavaBeanField javaBeanField) {
return findTypeArgumentsConstraints(
javaBeanField,
new TypeArgumentFieldLocation( javaBeanField ),
javaBeanField.getAnnotatedType()
);
}
/**
* 查找方法返回值的类型参数约束。
*/
protected Set<MetaConstraint<?>> findTypeAnnotationConstraints(JavaBeanExecutable<?> javaBeanExecutable) {
return findTypeArgumentsConstraints(
javaBeanExecutable,
new TypeArgumentReturnValueLocation( javaBeanExecutable ),
// 获取方法返回值的类型。如果是普通的Method,则最后执行Method.getAnnotatedReturnType();
// 如果是构造方法,执行Constructor.getAnnotatedReturnType()方法
javaBeanExecutable.getAnnotatedType()
);
}
/**
* 通过判断添加注解的元素是否有添加@Valid,如果有为级联,返回的CascadingMetaDataBuilder的cascading为true
*/
private CascadingMetaDataBuilder findCascadingMetaData(JavaBeanParameter javaBeanParameter) {
Map<TypeVariable<?>, CascadingMetaDataBuilder> containerElementTypesCascadingMetaData = getTypeParametersCascadingMetadata( javaBeanParameter.getAnnotatedType(),
javaBeanParameter.getTypeParameters() );
try {
return getCascadingMetaData( javaBeanParameter, containerElementTypesCascadingMetaData );
}
catch (ArrayIndexOutOfBoundsException ex) {
LOG.warn( MESSAGES.constraintOnConstructorOfNonStaticInnerClass(), ex );
return CascadingMetaDataBuilder.nonCascading();
}
}
/**
* 查找级联元数据。通过判断添加注解的元素是否有添加@Valid,如果有为级联,返回的CascadingMetaDataBuilder的cascading为true
* @param javaBeanField
* @return
*/
private CascadingMetaDataBuilder findCascadingMetaData(JavaBeanField javaBeanField) {
Map<TypeVariable<?>, CascadingMetaDataBuilder> containerElementTypesCascadingMetaData = getTypeParametersCascadingMetadata(
javaBeanField.getAnnotatedType(),
// 获取属性泛型类或接口的泛型声明所声明的类型参数。如ArrayList<String> list属性值,此方法返回[String]
javaBeanField.getTypeParameters() );
return getCascadingMetaData( javaBeanField, containerElementTypesCascadingMetaData );
}
/**
* 查找级联元数据。通过判断添加注解的元素是否有添加@Valid,如果有为级联,返回的CascadingMetaDataBuilder的cascading为true
* @param javaBeanExecutable
* @return
*/
private CascadingMetaDataBuilder findCascadingMetaData(JavaBeanExecutable<?> javaBeanExecutable) {
Map<TypeVariable<?>, CascadingMetaDataBuilder> containerElementTypesCascadingMetaData = getTypeParametersCascadingMetadata( javaBeanExecutable.getAnnotatedType(),
javaBeanExecutable.getTypeParameters() );
return getCascadingMetaData( javaBeanExecutable, containerElementTypesCascadingMetaData );
}
private Map<TypeVariable<?>, CascadingMetaDataBuilder> getTypeParametersCascadingMetadata(AnnotatedType annotatedType,
TypeVariable<?>[] typeParameters) {
// 如果是AnnotatedArrayType,返回空Map
if ( annotatedType instanceof AnnotatedArrayType ) {
return getTypeParametersCascadingMetaDataForArrayType( (AnnotatedArrayType) annotatedType );
}
// 被注解的参数化类型
else if ( annotatedType instanceof AnnotatedParameterizedType ) {
return getTypeParametersCascadingMetaDataForParameterizedType( (AnnotatedParameterizedType) annotatedType, typeParameters );
}
else {
return Collections.emptyMap();
}
}
/**
* 获取参数化类型的类型参数级联元数据
*/
private Map<TypeVariable<?>, CascadingMetaDataBuilder> getTypeParametersCascadingMetaDataForParameterizedType(
AnnotatedParameterizedType annotatedParameterizedType, TypeVariable<?>[] typeParameters) {
Map<TypeVariable<?>, CascadingMetaDataBuilder> typeParametersCascadingMetadata = CollectionHelper.newHashMap( typeParameters.length );
AnnotatedType[] annotatedTypeArguments = annotatedParameterizedType.getAnnotatedActualTypeArguments();
int i = 0;
for ( AnnotatedType annotatedTypeArgument : annotatedTypeArguments ) {
Map<TypeVariable<?>, CascadingMetaDataBuilder> nestedTypeParametersCascadingMetadata = getTypeParametersCascadingMetaDataForAnnotatedType(
annotatedTypeArgument );
typeParametersCascadingMetadata.put( typeParameters[i], new CascadingMetaDataBuilder( annotatedParameterizedType.getType(), typeParameters[i],
annotatedTypeArgument.isAnnotationPresent( Valid.class ), nestedTypeParametersCascadingMetadata,
getGroupConversions( annotatedTypeArgument ) ) );
i++;
}
return typeParametersCascadingMetadata;
}
private Map<TypeVariable<?>, CascadingMetaDataBuilder> getTypeParametersCascadingMetaDataForArrayType(AnnotatedArrayType annotatedArrayType) {
return Collections.emptyMap();
}
private Map<TypeVariable<?>, CascadingMetaDataBuilder> getTypeParametersCascadingMetaDataForAnnotatedType(AnnotatedType annotatedType) {
if ( annotatedType instanceof AnnotatedArrayType ) {
return getTypeParametersCascadingMetaDataForArrayType( (AnnotatedArrayType) annotatedType );
}
else if ( annotatedType instanceof AnnotatedParameterizedType ) {
return getTypeParametersCascadingMetaDataForParameterizedType( (AnnotatedParameterizedType) annotatedType,
ReflectionHelper.getClassFromType( annotatedType.getType() ).getTypeParameters() );
}
else {
return Collections.emptyMap();
}
}
/**
* 查找参数的类型实参约束
*/
protected Set<MetaConstraint<?>> findTypeAnnotationConstraintsForExecutableParameter(JavaBeanExecutable<?> javaBeanExecutable,
JavaBeanParameter javaBeanParameter) {
try {
return findTypeArgumentsConstraints(
javaBeanExecutable,
new TypeArgumentExecutableParameterLocation( javaBeanExecutable, javaBeanParameter.getIndex() ),
javaBeanParameter.getAnnotatedType()
);
}
catch (ArrayIndexOutOfBoundsException ex) {
LOG.warn( MESSAGES.constraintOnConstructorOfNonStaticInnerClass(), ex );
return Collections.emptySet();
}
}
/**
* 通过判断添加注解的元素是否有添加@Valid,如果有为级联,返回的CascadingMetaDataBuilder的cascading为true
* @param annotatedElement
* @param containerElementTypesCascadingMetaData
* @return
*/
private CascadingMetaDataBuilder getCascadingMetaData(JavaBeanAnnotatedElement annotatedElement,
Map<TypeVariable<?>, CascadingMetaDataBuilder> containerElementTypesCascadingMetaData) {
return CascadingMetaDataBuilder.annotatedObject( annotatedElement.getType(), annotatedElement.isAnnotationPresent( Valid.class ),
containerElementTypesCascadingMetaData, getGroupConversions( annotatedElement.getAnnotatedType() ) );
}
}
在
Spring validation参数校验原理解析之Controller控制器参数校验中@RequestBody参数校验实现原理-CSDN博客
的3.1中介绍了BeanMetaDataManagerImpl的getBeanMetaData(Class<T> beanClass)方法,对应的beanClass首次调用时,会先调用createBeanMetaData()方法,调用getBeanConfigurationForHierarchy()方法,遍历beanClass及其父类,执行provider.getBeanConfiguration(clazz),从而执行AnnotationMetaDataProvider的getBeanConfiguration()方法,获取beanClass对应的约束元数据信息。
getFieldMetaData(beanClass):遍历类中定义的属性,解析属性中添加的约束注解,封装成ConstrainedElement对象;
getMethodMetaData(beanClass):遍历类中定义的方法,排查静态方法和合成方法,解析方法添加的约束注解、入参及返回值(自动判断是作用在入参还是返回值上),封装成ConstrainedExecutable对象。ConstrainedExecutable也实现了ConstrainedElement接口;
getConstructorMetaData(beanClass):遍历构造方法,处理同getMethodMetaData(beanClass);
getClassLevelConstraints(beanClass):解析类中添加的约束注解,封装成COnstraintDescriptor对象;最终转换成ConstrainedType对象。ConstrainedType也实现了ConstrainedElement接口;
在findConstraintAnnotations(Constrainable constrainable,A annotation,ConstraintLocationKind type)方法中,会执行ConstraintHelper.isConstraintAnnotation()【执行constraintCreationContext.getConstraintHelper().isConstraintAnnotation( annotationType )】
/**
* ConstraintHelper类的isConstraintAnnotation()方法。判断annotationType是否为约束注解
*/
public boolean isConstraintAnnotation(Class<? extends Annotation> annotationType) {
// BuiltinConstraint.isBuiltin()【BuiltinConstraint为枚举类,列举了validation的所有约束字段。从而判断当前的参数是否为BuiltinConstraint枚举中的注解】
if ( isBuiltinConstraint( annotationType ) ) {
return true;
}
// 判断annotationType是否添加了@Constraint注解
if ( annotationType.getAnnotation( Constraint.class ) == null ) {
return false;
}
return externalConstraints.computeIfAbsent( annotationType, a -> {
assertMessageParameterExists( a );
assertGroupsParameterExists( a );
assertPayloadParameterExists( a );
assertValidationAppliesToParameterSetUpCorrectly( a );
assertNoParameterStartsWithValid( a );
return Boolean.TRUE;
} );
}
isBuiltinConstraint() -> BuiltinConstraint.isBuiltin()。BuiltinConstraint为枚举类,列举了validation的所有约束字段。从而判断当前的参数是否属于BuiltinConstraint枚举中的注解。
BuiltinConstraint.java
enum BuiltinConstraint {
JAVAX_VALIDATION_CONSTRAINTS_MIN("javax.validation.constraints.Min"),
JAVAX_VALIDATION_CONSTRAINTS_MAX("javax.validation.constraints.Max"),
JAVAX_VALIDATION_CONSTRAINTS_NEGATIVE("javax.validation.constraints.Negative"),
JAVAX_VALIDATION_CONSTRAINTS_NEGATIVE_OR_ZERO("javax.validation.constraints.NegativeOrZero"),
JAVAX_VALIDATION_CONSTRAINTS_NOT_BLANK("javax.validation.constraints.NotBlank"),
JAVAX_VALIDATION_CONSTRAINTS_NOT_EMPTY("javax.validation.constraints.NotEmpty"),
JAVAX_VALIDATION_CONSTRAINTS_NOT_NULL("javax.validation.constraints.NotNull"),
JAVAX_VALIDATION_CONSTRAINTS_NULL("javax.validation.constraints.Null"),
// 省略其他,只列出部分
}
结尾
以上为本次分享的Spring validation参加校验的核心类的源码分析。限于篇幅,本篇就先分享到这里,希望对你有所帮助。
关于本篇内容你有什么自己的想法或独到见解,欢迎在评论区一起交流探讨下吧。