Hibernate Validator源码解析

一、引言

问题:在代码编写的过程中,数据值的校验在JavaEE三层架构(展示层、业务层、数据访问层)均有涉及,各层的校验需求又是不尽相同的,因此往往会伴随着代码冗余,重复的校验逻辑出现在三层代码中。
在这里插入图片描述
简介:JSR-303 Bean-Validator伴随着此类问题应运而生,Hibernate-Validator就是一个遵循JSR-303规范的优秀实践。
在这里插入图片描述
图片截取自Hibernate Validator 官方pdf文档。

Hibernate-Validator提供了较为完善、便捷的校验方式解决了代码校验问题。 常用于提供字段的校验,比如字段非空、字段长度限制、邮箱验证等等。

二、测试实例

下面引用Hibernate-Validator源码中ValidatorTest测试类下的方法为例:

class A {
   @NotNull
   String b;

   @Valid
   C c;

   @Valid
   D d;
}
@GroupSequence({ TestGroup.class, C.class })
class C {
   @Pattern(regexp = "[0-9]+", groups = TestGroup.class)
   @Length(min = 2)
   String id;

   C(String id) {
      this.id = id;
   }
}
@Test
public void testValidate() {
    ValidatorFactory factory = configuration.buildValidatorFactory(); 
    Validator validator = factory.getValidator();
    A testInstance = new A();
    testInstance.c = new C( "aaa" );
    Set<ConstraintViolation<SerializableClass>> constraintViolations = validator.validate( testInstance );
    Set<ConstraintViolation<A>> constraintViolations = validator.validateProperty( testInstance, "c.id" );
    Set<ConstraintViolation<A>> constraintViolations = validator.validateValue( A.class, "c.id", "aaa" );
}

由上例可以看出,Hibernate-Validator主要是将JSR-303内置的约束以及Hibernate-Validator扩展的自定义约束通过注解的形式添加到属性上,来实现对对象内属性的校验功能。下面我们将通过上述例子拆分及解析校验实现的流程及细节,本文使用Hibernate-Validator下的7.0.1.Final版本解释源码。

三. Hibernate-Validator具体实现

1. 获取Validator实例

想要对对象进行校验,首先需要获得一个Validator校验器实例,由上述代码可知

ValidatorFactory factory = configuration.buildValidatorFactory();
Validator validator = factory.getValidator();

校验器获取方法在代码实现上较为简单,主要是遵循Java内部的SPI机制实现Java提供的相关接口实现。

主要实现分为两步:

a. validatorFactory 工厂创建

public static ValidatorFactory buildDefaultValidatorFactory() {
    return byDefaultProvider().configure().buildValidatorFactory();
}

// 构建相关配置文件
public Configuration<?> configure() {
    // ValidationProviderResolver 的主要作用是确定环境下可用的 ValidationProvider 列表
    // 其唯一实现是 jakarta.validation.Validation 下的内部类 DefaultValidationProviderResolver 
    ValidationProviderResolver resolver = this.resolver == null ? this.getDefaultValidationProviderResolver() : this.resolver;

    List validationProviders;
    try {
        // ValidationProvider的作用是提供程序校验器,通过其下的buildValidatorFactory方法构建ValidatorFactory工厂
        // Hibernate-Validator对其提供了唯一的实现类HibernateValidator构建并返回工厂实现ValidatorFactoryImpl
        validationProviders = resolver.getValidationProviders();
    } catch (ValidationException var6) {
        throw var6;
    } catch (RuntimeException var7) {
        throw new ValidationException("Unable to get available provider resolvers.", var7);
    }

    if (validationProviders.isEmpty()) {
        String msg = "Unable to create a Configuration, because no Jakarta Bean Validation provider could be found. Add a provider like Hibernate Validator (RI) to your classpath.";
        throw new NoProviderFoundException(msg);
    } else {
        try {
            // 从 ValidationProvider 中获取相关通用配置
            Configuration<?> config = ((ValidationProvider)resolver.getValidationProviders().get(0)).createGenericConfiguration(this);
            return config;
        } catch (RuntimeException var5) {
            throw new ValidationException("Unable to instantiate Configuration.", var5);
        }
    }
}

// 根据配置文件构建用于创建Validator的工厂并初始化相关参数
public final ValidatorFactory buildValidatorFactory() {
   loadValueExtractorsFromServiceLoader();
   // 解析Validation.xml,如何存在则解析其配置
   parseValidationXml();

   for ( ValueExtractorDescriptor valueExtractorDescriptor : valueExtractorDescriptors.values() ) {
      validationBootstrapParameters.addValueExtractorDescriptor( valueExtractorDescriptor );
   }

   ValidatorFactory factory = null;
   try {
      // 判断是否指定了Validator,指定了Validator则直接返回Factory
      if ( isSpecificProvider() ) {
         factory = validationBootstrapParameters.getProvider().buildValidatorFactory( this );
      }
      else {
         // 判断是否指定了 ValidatorProvider
         final Class<? extends ValidationProvider<?>> providerClass = validationBootstrapParameters.getProviderClass();
         if ( providerClass != null ) {
            for ( ValidationProvider<?> provider : providerResolver.getValidationProviders() ) {
               if ( providerClass.isAssignableFrom( provider.getClass() ) ) {
                  factory = provider.buildValidatorFactory( this );
                  break;
               }
            }
            if ( factory == null ) {
               throw LOG.getUnableToFindProviderException( providerClass );
            }
         }
         else {
            List<ValidationProvider<?>> providers = providerResolver.getValidationProviders();
            assert providers.size() != 0; // I run therefore I am
            // 构建 ValidatorFactory 时初始化了很多对象,包括方法校验配置、分组排序、注解到注解校验实现的映射等
            factory = providers.get( 0 ).buildValidatorFactory( this );
         }
      }
   }
   finally {
      // close all input streams opened by this configuration
      for ( InputStream in : configurationStreams ) {
         try {
            in.close();
         }
         catch (IOException io) {
            LOG.unableToCloseInputStream();
         }
      }
   }

   return factory;
}

b. 获取Validator实例

@Override
// getValidator 是 ValidatorFactoryImpl 下最重要的方法,用于获取 Validator 实例
public Validator getValidator() {
   return createValidator(
         constraintCreationContext.getConstraintValidatorManager().getDefaultConstraintValidatorFactory(),
         constraintCreationContext,
         validatorFactoryScopedContext,
         methodValidationConfiguration
   );
}

2. Validator校验

由实例中列举的validator校验方法可知,Validator校验分为三种类型,分别是:

  1. validate:针对所有属性进行校验;
  2. validateProperty:针对某一个具体属性进行校验;
  3. validateValue:针对某一个具体属性及特定值进行校验。

本文选用validate的相关校验流程及源码进行解析,源码功能使用代码注释的方式解释。

validate具体校验流程如下所示:

  1. 执行ValidatorImpl下的validate方法,封装validationContext(校验器上下文)、valueContext(校验对象上下文)及validationOrder(校验群组及排序信息)数据内容,方便后续调用。
// 校验对象下的所有约束是否正常
@Override
public final <T> Set<ConstraintViolation<T>> validate(T object, Class<?>... groups) {
    // 校验对象是否为空
    Contracts.assertNotNull(object, MESSAGES.validatedObjectMustNotBeNull());
    // 校验Class Group是否为空
    sanityCheckGroups(groups);

    @SuppressWarnings("unchecked")
    // 获取对象的Class
    Class<T> rootBeanClass = (Class<T>) object.getClass();
    // 通过反射获取对象内所有Field、Method、Class相关的元数据信息
    BeanMetaData<T> rootBeanMetaData = beanMetaDataManager.getBeanMetaData(rootBeanClass);

    // 判断是否含有约束,无约束则直接返回
    if (!rootBeanMetaData.hasConstraints()) {
        return Collections.emptySet();
    }

    // 将对象元数据和实际对象内容封装成一个完成的ValidationContext
    BaseBeanValidationContext<T> validationContext = getValidationContextBuilder().forValidate(rootBeanClass,
        rootBeanMetaData, object);

    // 接口分组排序,分组排序决定了哪个Group先校验,哪个Group后校验,用于处理有先后关系的校验
    ValidationOrder validationOrder = determineGroupValidationOrder(groups);
    // 填充校验对象上下文信息
    BeanValueContext<?, Object> valueContext = ValueContexts.getLocalExecutionContextForBean(
        validatorScopedContext.getParameterNameProvider(), object, validationContext.getRootBeanMetaData(),
        PathImpl.createRootPath());
    // 根据校验文件必要信息进行校验操作
    return validateInContext(validationContext, valueContext, validationOrder);
}
  1. 执行ValidatorImpl下的validateInContext方法,根据传入对象的群组、级联信息分别进行校验
private <T, U> Set<ConstraintViolation<T>> validateInContext(BaseBeanValidationContext<T> validationContext,
    BeanValueContext<U, Object> valueContext, ValidationOrder validationOrder) {
    // 如果Bean为null则直接返回空
    if (valueContext.getCurrentBean() == null) {
        return Collections.emptySet();
    }

    // 取出当前Bean元数据
    BeanMetaData<U> beanMetaData = valueContext.getCurrentBeanMetaData();
    if (beanMetaData.isDefaultGroupSequenceRedefined()) {
        validationOrder.assertDefaultGroupSequenceIsExpandable(
            beanMetaData.getDefaultGroupSequence(valueContext.getCurrentBean()));
    }

    // 校验当前对象内的约束内容
    Iterator<Group> groupIterator = validationOrder.getGroupIterator();
    while (groupIterator.hasNext()) {
        Group group = groupIterator.next();
        valueContext.setCurrentGroup(group.getDefiningClass());
        // 校验当前对象
        validateConstraintsForCurrentGroup(validationContext, valueContext);
        // 判断约束校验是否失败
        if (shouldFailFast(validationContext)) {
            return validationContext.getFailingConstraints();
        }
    }
    // 级联校验,即校验一个对象内可能存在的需要校验的其他对象
    groupIterator = validationOrder.getGroupIterator();
    while (groupIterator.hasNext()) {
        Group group = groupIterator.next();
        valueContext.setCurrentGroup(group.getDefiningClass());
        // 校验级联对象
        validateCascadedConstraints(validationContext, valueContext);
        // 判断约束校验是否失败
        if (shouldFailFast(validationContext)) {
            return validationContext.getFailingConstraints();
        }
    }

    // 如果需要校验的对象包含GroupSequece,按次序校验则走以下方法
    Iterator<Sequence> sequenceIterator = validationOrder.getSequenceIterator();
    while (sequenceIterator.hasNext()) {
        Sequence sequence = sequenceIterator.next();
        for (GroupWithInheritance groupOfGroups : sequence) {
            int numberOfViolations = validationContext.getFailingConstraints().size();

            for (Group group : groupOfGroups) {
                valueContext.setCurrentGroup(group.getDefiningClass());
                // 校验对象
                validateConstraintsForCurrentGroup(validationContext, valueContext);
                // 判断约束校验是否失败
                if (shouldFailFast(validationContext)) {
                    return validationContext.getFailingConstraints();
                }
                // 校验级联对象
                validateCascadedConstraints(validationContext, valueContext);
                // 判断约束校验是否失败
                if (shouldFailFast(validationContext)) {
                    return validationContext.getFailingConstraints();
                }
            }
            if (validationContext.getFailingConstraints().size() > numberOfViolations) {
                break;
            }
        }
    }
    return validationContext.getFailingConstraints();
}
  1. 根据校验属性的Group执行相应校验方法
private void validateConstraintsForCurrentGroup(BaseBeanValidationContext<?> validationContext,
    BeanValueContext<?, Object> valueContext) {
    if (!valueContext.validatingDefault()) {
        // 如果校验的group非Default Group,走该校验方法
        validateConstraintsForNonDefaultGroup(validationContext, valueContext);
    }
    else {
        // 如果校验的group为Default Group,走该校验方法
        validateConstraintsForDefaultGroup(validationContext, valueContext);
    }
}
  1. 解析当前对象的继承结构,根据继承结构和默认的GroupSequence进行校验
// 默认约束校验
private <U> void validateConstraintsForDefaultGroup(BaseBeanValidationContext<?> validationContext,
    BeanValueContext<U, Object> valueContext) {
    // 获取currentBeanMetaData对象校验当前对象内容
    final BeanMetaData<U> beanMetaData = valueContext.getCurrentBeanMetaData();
    final Map<Class<?>, Class<?>> validatedInterfaces = new HashMap<>();

    // 评估类的继承结构中每个类的约束,依次校验该类及其父类约束
    for (Class<? super U> clazz : beanMetaData.getClassHierarchy()) {
        BeanMetaData<? super U> hostingBeanMetaData = beanMetaDataManager.getBeanMetaData(clazz);
        boolean defaultGroupSequenceIsRedefined = hostingBeanMetaData.isDefaultGroupSequenceRedefined();

        // 如果默认的GroupSequence被重新定义,说明需要对属性校验排序处理,则走以下方法进行校验
        if (defaultGroupSequenceIsRedefined) {
            Iterator<Sequence> defaultGroupSequence = hostingBeanMetaData
                .getDefaultValidationSequence(valueContext.getCurrentBean());
            Set<MetaConstraint<?>> metaConstraints = hostingBeanMetaData.getMetaConstraints();

            while (defaultGroupSequence.hasNext()) {
                // 区分GroupSequence进行校验
                for (GroupWithInheritance groupOfGroups : defaultGroupSequence.next()) {
                    boolean validationSuccessful = true;

                    for (Group defaultSequenceMember : groupOfGroups) {
                        // 遍历GroupSequence下的Group进行校验
                        validationSuccessful = validateConstraintsForSingleDefaultGroupElement(validationContext,
                            valueContext, validatedInterfaces, clazz, metaConstraints, defaultSequenceMember)
                            && validationSuccessful;
                    }

                    validationContext.markCurrentBeanAsProcessed(valueContext);

                    if (!validationSuccessful) {
                        break;
                    }
                }
            }
        }
        // fast path in case the default group sequence hasn't been redefined
        else {
            // 查询当前Bean下可以直接进行校验的属性
            Set<MetaConstraint<?>> metaConstraints = hostingBeanMetaData.getDirectMetaConstraints();
            // 执行校验
            validateConstraintsForSingleDefaultGroupElement(validationContext, valueContext, validatedInterfaces,
                clazz, metaConstraints, Group.DEFAULT_GROUP);
            validationContext.markCurrentBeanAsProcessed(valueContext);
        }

        // 层级中的所有约束均完成校验,则停止校验
        if (defaultGroupSequenceIsRedefined) {
            break;
        }
    }
}
  1. 循环校验对象的每个属性
private <U> boolean validateConstraintsForSingleDefaultGroupElement(BaseBeanValidationContext<?> validationContext,
    ValueContext<U, Object> valueContext, final Map<Class<?>, Class<?>> validatedInterfaces, Class<? super U> clazz,
    Set<MetaConstraint<?>> metaConstraints, Group defaultSequenceMember) {
    boolean validationSuccessful = true;

    valueContext.setCurrentGroup(defaultSequenceMember.getDefiningClass());

    // 循环校验对象的每个属性
    for (MetaConstraint<?> metaConstraint : metaConstraints) {
        // HV-466, an interface implemented more than one time in the hierarchy has to be validated only one
        // time. An interface can define more than one constraint, we have to check the class we are validating.
        final Class<?> declaringClass = metaConstraint.getLocation().getDeclaringClass();
        if (declaringClass.isInterface()) {
            Class<?> validatedForClass = validatedInterfaces.get(declaringClass);
            if (validatedForClass != null && !validatedForClass.equals(clazz)) {
                continue;
            }
            validatedInterfaces.put(declaringClass, clazz);
        }

        // 校验类非interface接口则正常校验
        boolean tmp = validateMetaConstraint(validationContext, valueContext, valueContext.getCurrentBean(),
            metaConstraint);
        // 快速失败
        if (shouldFailFast(validationContext)) {
            return false;
        }

        validationSuccessful = validationSuccessful && tmp;
    }
    return validationSuccessful;
}
  1. 判断对象是否满足校验条件并对对象进行校验
private boolean validateMetaConstraint(BaseBeanValidationContext<?> validationContext,
    ValueContext<?, Object> valueContext, Object parent, MetaConstraint<?> metaConstraint) {
    BeanValueContext.ValueState<Object> originalValueState = valueContext.getCurrentValueState();
    valueContext.appendNode(metaConstraint.getLocation());
    boolean success = true;
    // 判断待校验文件是否满足校验条件,如对象属性分组数及校验数是否匹配,校验分组是否与当前分组匹配等
    if (isValidationRequired(validationContext, valueContext, metaConstraint)) {

        if (parent != null) {
            valueContext.setCurrentValidatedValue(valueContext.getValue(parent, metaConstraint.getLocation()));
        }

        // 对象属性校验
        success = metaConstraint.validateConstraint(validationContext, valueContext);

        validationContext.markConstraintProcessed(valueContext.getCurrentBean(), valueContext.getPropertyPath(),
            metaConstraint);
    }

    // 对象属性校验完成后重置校验数据
    valueContext.resetValueState(originalValueState);

    return success;
}
  1. 具体对象值提取校验逻辑
public boolean validateConstraint(ValidationContext<?> validationContext, ValueContext<?, Object> valueContext) {
    boolean success = true;
    // 提取集合内容器循环校验
    if (valueExtractionPath != null) {
        Object valueToValidate = valueContext.getCurrentValidatedValue();
        if (valueToValidate != null) {
            TypeParameterValueReceiver receiver = new TypeParameterValueReceiver(validationContext, valueContext,
                valueExtractionPath);
            ValueExtractorHelper.extractValues(valueExtractionPath.getValueExtractorDescriptor(), valueToValidate,
                receiver);
            success = receiver.isSuccess();
        }
    }
    // 常规校验流程
    else {
        success = doValidateConstraint(validationContext, valueContext);
    }
    return success;
}
  1. 失败异常处理
public final boolean validateConstraints(ValidationContext<?> validationContext, ValueContext<?, ?> valueContext) {
    List<ConstraintValidatorContextImpl> violatedConstraintValidatorContexts = new ArrayList<>(5);
    // 属性值执行校验
    validateConstraints(validationContext, valueContext, violatedConstraintValidatorContexts);
    // 如果violatedConstraintValidatorContexts集合不为空,则说明校验失败,校验失败属性处理
    if (!violatedConstraintValidatorContexts.isEmpty()) {
        for (ConstraintValidatorContextImpl constraintValidatorContext : violatedConstraintValidatorContexts) {
            for (ConstraintViolationCreationContext constraintViolationCreationContext : constraintValidatorContext
                .getConstraintViolationCreationContexts()) {
                validationContext.addConstraintFailure(valueContext, constraintViolationCreationContext,
                    constraintValidatorContext.getConstraintDescriptor());
            }
        }
        return false;
    }
    return true;
}
  1. 获取属性校验对应校验器及构建约束校验器上下文
protected void validateConstraints(ValidationContext<?> validationContext, ValueContext<?, ?> valueContext,
    Collection<ConstraintValidatorContextImpl> violatedConstraintValidatorContexts) {

    if (LOG.isTraceEnabled()) {
        LOG.tracef("Validating value %s against constraint defined by %s.", valueContext.getCurrentValidatedValue(),
            descriptor);
    }

    // 获取对象相关的Validator校验器,注解与校验器的映射在ValidatorImpl初始化时就已经取出,存在校验上下文对象中。
    // 通过AbstractConstraintValidatorManagerImpl下的findMatchingValidatorDescriptor查询并匹配到对应属性。
    ConstraintValidator<B, ?> validator = getInitializedConstraintValidator(validationContext, valueContext);

    // 构建约束校验器上下文
    ConstraintValidatorContextImpl constraintValidatorContext = validationContext
        .createConstraintValidatorContextFor(descriptor, valueContext.getPropertyPath());

    // 校验,如果校验失败则加入集合violatedConstraintValidatorContexts
    if (validateSingleConstraint(valueContext, constraintValidatorContext, validator).isPresent()) {
        violatedConstraintValidatorContexts.add(constraintValidatorContext);
    }
}
  1. 通过筛选出的validator完成校验
protected final <V> Optional<ConstraintValidatorContextImpl> validateSingleConstraint(
    ValueContext<?, ?> valueContext, ConstraintValidatorContextImpl constraintValidatorContext,
    ConstraintValidator<A, V> validator) {
    boolean isValid;
    try {
        // 获取当前要校验的对象值value
        @SuppressWarnings("unchecked")
        V validatedValue = (V) valueContext.getCurrentValidatedValue();
        // 使用注解和属性类型对应的Validator进行校验
        isValid = validator.isValid(validatedValue, constraintValidatorContext);
    }
    catch (RuntimeException e) {
        if (e instanceof ConstraintDeclarationException) {
            throw e;
        }
        throw LOG.getExceptionDuringIsValidCallException(e);
    }
    if (!isValid) {
        // We do not add these violations yet, since we don't know how they are
        // going to influence the final boolean evaluation
        return Optional.of(constraintValidatorContext);
    }
    return Optional.empty();
}

上述代码即是从ValidatorImpl下的validator方法开始到实现注解属性校验的基础校验过程源码解析。
validateProperty和validateValue两种方法与validate方法差异不大,此处不进行过多赘述。

当校验对象中存在嵌套对象需要校验时,此时需要使用@Valid注解标注出需要校验的对象,通过级联校验功能进行校验。

private <T, U> Set<ConstraintViolation<T>> validateInContext(BaseBeanValidationContext<T> validationContext,
    BeanValueContext<U, Object> valueContext, ValidationOrder validationOrder) {
    // 级联校验,即校验一个对象内可能存在的需要校验的其他对象
    groupIterator = validationOrder.getGroupIterator();
    while (groupIterator.hasNext()) {
        Group group = groupIterator.next();
        valueContext.setCurrentGroup(group.getDefiningClass());
        // 校验级联对象
        validateCascadedConstraints(validationContext, valueContext);
        // 判断约束校验是否失败
        if (shouldFailFast(validationContext)) {
            return validationContext.getFailingConstraints();
        }
    }
    return validationContext.getFailingConstraints();
}
private void validateCascadedConstraints(BaseBeanValidationContext<?> validationContext,
    ValueContext<?, Object> valueContext) {
    // 获取当前对象下的可校验内容
    Validatable validatable = valueContext.getCurrentValidatable();
    BeanValueContext.ValueState<Object> originalValueState = valueContext.getCurrentValueState();

    // 校验当前对象下注释了@Valid的属性或方法参数
    for (Cascadable cascadable : validatable.getCascadables()) {
        valueContext.appendNode(cascadable);
        // 确认级联校验对象处于可校验状态
        if (isCascadeRequired(validationContext, valueContext.getCurrentBean(), valueContext.getPropertyPath(),
            cascadable.getConstraintLocationKind())) {
            Object value = getCascadableValue(validationContext, valueContext.getCurrentBean(), cascadable);
            CascadingMetaData cascadingMetaData = cascadable.getCascadingMetaData();

            if (value != null) {
                CascadingMetaData effectiveCascadingMetaData = cascadingMetaData
                    .addRuntimeContainerSupport(valueExtractorManager, value.getClass());

                // 校验被@Valid注释的级联属性,递归validateInContext方法实现递归级联校验
                if (effectiveCascadingMetaData.isCascading()) {
                    validateCascadedAnnotatedObjectForCurrentGroup(value, validationContext, valueContext,
                        effectiveCascadingMetaData);
                }

                // Container集合数据特殊处理
                if (effectiveCascadingMetaData.isContainer()) {
                    ContainerCascadingMetaData containerCascadingMetaData = effectiveCascadingMetaData
                        .as(ContainerCascadingMetaData.class);

                    if (containerCascadingMetaData.hasContainerElementsMarkedForCascading()) {
                        // 校验Container内元素约束
                        validateCascadedContainerElementsForCurrentGroup(value, validationContext, valueContext,
                            containerCascadingMetaData.getContainerElementTypesCascadingMetaData());
                    }
                }
            }
        }

        // 重置valueContext值内容
        valueContext.resetValueState(originalValueState);
    }
}
private void validateCascadedAnnotatedObjectForCurrentGroup(Object value,
    BaseBeanValidationContext<?> validationContext, ValueContext<?, Object> valueContext,
    CascadingMetaData cascadingMetaData) {
    Class<?> originalGroup = valueContext.getCurrentGroup();
    Class<?> currentGroup = cascadingMetaData.convertGroup(originalGroup);
    // 判断数据是否已经校验过或者校验是否已经失败
    if (validationContext.isBeanAlreadyValidated(value, currentGroup, valueContext.getPropertyPath())
        || shouldFailFast(validationContext)) {
        return;
    }

    ValidationOrder validationOrder = validationOrderGenerator.getValidationOrder(currentGroup,
        currentGroup != originalGroup);

    BeanValueContext<?, Object> cascadedValueContext = buildNewLocalExecutionContext(valueContext, value);
    // 递归校验
    validateInContext(validationContext, cascadedValueContext, validationOrder);
}

3. Validator功能拓展

Validator除基础的校验流程外,为了强化功能以满足更多场景的需要,校验流程中还提供了诸如Group(群组)、Sequence(优先级)等功能,下面将解读这些功能在校验中的相关类源码。

  1. Group(群组)

a. 为类中的属性约束定义群组

@Data
public class Driver extends Person {
    @Min(value = 18, message = "You have to be 18 to drive a car", groups = DriverChecks.class)
    public int age;

    public Driver(String name) {
        super(name);
    }
}

b. 封装校验群组及校验顺序信息到ValidationOrder对象中

public ValidationOrder getValidationOrder(Collection<Class<?>> groups) {
   // 如果Group为空则抛出异常
   if ( groups == null || groups.size() == 0 ) {
      throw LOG.getAtLeastOneGroupHasToBeSpecifiedException();
   }

   // Group集合下仅包含默认Group则直接返回
   if ( groups.size() == 1 && groups.contains( Default.class ) ) {
      return ValidationOrder.DEFAULT_GROUP;
   }
   // 所有的group类均为接口类,如果存在非接口Group则抛出异常
   for ( Class<?> clazz : groups ) {
      if ( !clazz.isInterface() ) {
         throw LOG.getGroupHasToBeAnInterfaceException( clazz );
      }
   }

   // 根据集合groups填充validationOrder群组及排序信息
   DefaultValidationOrder validationOrder = new DefaultValidationOrder();
   for ( Class<?> clazz : groups ) {
      if ( Default.class.equals( clazz ) ) { 
         validationOrder.insertGroup( Group.DEFAULT_GROUP );
      }
      else if ( isGroupSequence( clazz ) ) {
         insertSequence( clazz, clazz.getAnnotation( GroupSequence.class ).value(), true, validationOrder );
      }
      else {
         Group group = new Group( clazz );
         validationOrder.insertGroup( group );
         insertInheritedGroups( clazz, validationOrder );
      }
   }

   return validationOrder;
}

c. validateInContext方法通过遍历ValidationOrder对象中的分组信息和序列信息进行校验

// 校验当前对象内的约束内容
Iterator<Group> groupIterator = validationOrder.getGroupIterator();
while (groupIterator.hasNext()) {
    …………
}
// 如果需要校验的对象包含GroupSequece,按次序校验则走以下方法
Iterator<Sequence> sequenceIterator = validationOrder.getSequenceIterator();
while (sequenceIterator.hasNext()) {
    …………
}

d. 后续指定Group后直接执行循环校验,校验分组与指定分组相同的属性。

private boolean isValidationRequired(BaseBeanValidationContext<?> validationContext,
    ValueContext<?, ?> valueContext, MetaConstraint<?> metaConstraint) {
    if (!validationContext.appliesTo(metaConstraint)) {
        return false;
    }
    if (validationContext.hasMetaConstraintBeenProcessed(valueContext.getCurrentBean(),
        valueContext.getPropertyPath(), metaConstraint)) {
        return false;
    }
    // 分组校验,如果需要校验的属性分组与当前正在校验分组不同,则不进行校验
    if (!metaConstraint.getGroupList().contains(valueContext.getCurrentGroup())) {
        return false;
    }
    return isReachable(validationContext, valueContext.getCurrentBean(), valueContext.getPropertyPath(),
        metaConstraint.getConstraintLocationKind());
}

分组校验通过对Validator注解增加分组的方式,限定了校验需要生效的范围,在调用validator方法时指定本次校验的分组,即可指定哪些方法需要校验。

  1. Sequence(序列)

用户可以通过GroupSequence的方式指定分组的优先级,高优先级的分组可以优先执行校验逻辑。

private void insertSequence(Class<?> sequenceClass, Class<?>[] sequenceElements, boolean cache, DefaultValidationOrder validationOrder) {
   Sequence sequence = cache ? resolvedSequences.get( sequenceClass ) : null;
   if ( sequence == null ) {
      // 解析校验对象的GroupSequence校验优先级数据
      sequence = resolveSequence( sequenceClass, sequenceElements, new ArrayList<Class<?>>() );
      // 如果存在分组继承关系,则检查分组继承关系新增Group
      sequence.expandInheritedGroups();

      // 缓存校验优先级信息
      if ( cache ) {
         final Sequence cachedResolvedSequence = resolvedSequences.putIfAbsent( sequenceClass, sequence );
         if ( cachedResolvedSequence != null ) {
            sequence = cachedResolvedSequence;
         }
      }
   }
   validationOrder.insertSequence( sequence );
}

4. 自定义约束

除了Hibernate-Validator提供的约束外,用户在开发过程中经常需要基于自身业务需求自定义约束。

基于Hibernate-Validator框架拓展validator约束功能较为简单,仅需实现其自定义约束的两个部分,注解及其注解的约束实现。

注解是否为约束注解的解析实现在BeanMetaData对象的构造过程中,具体实现在org.hibernate.validator.internal.metadata.provider.AnnotationMetaDataProvider类下的findConstraintAnnotations方法中:

protected <A extends Annotation> List<ConstraintDescriptorImpl<?>> findConstraintAnnotations(Member member,
      A annotation,
      ElementType type) {
   if ( annotation.annotationType().getPackage().getName().equals( "jdk.internal" ) ) {
      return Collections.emptyList();
   }

   List<ConstraintDescriptorImpl<?>> constraintDescriptors = newArrayList();

   List<Annotation> constraints = newArrayList();
   Class<? extends Annotation> annotationType = annotation.annotationType();
   if ( constraintHelper.isConstraintAnnotation( annotationType ) ) {
      constraints.add( annotation );
   }
   else if ( constraintHelper.isMultiValueConstraint( annotationType ) ) {
      constraints.addAll( constraintHelper.getConstraintsFromMultiValueConstraint( annotation ) );
   }

   for ( Annotation constraint : constraints ) {
      final ConstraintDescriptorImpl<?> constraintDescriptor = buildConstraintDescriptor(
            member, constraint, type
      );
      constraintDescriptors.add( constraintDescriptor );
   }
   return constraintDescriptors;
}

保证注解满足constraintHelper.isConstraintAnnotation方法中的要求即可,包括其中必要参数及注解的校验。

public boolean isConstraintAnnotation(Class<? extends Annotation> annotationType) {
	// 查询是否是Hibernate-Validator自身约束,是则直接返回true
    if (isBuiltinConstraint(annotationType)) {
        return true;
    }
    
	// 自定义约束检查注解及参数是否合法
    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;
    });
}

约束的实现类则可直接在注解类中通过 @Constraint(validatedBy = {……}) 指定,本文在此不进行过多赘述。

5. 结语

Hibernate-Validator是一种较为优雅的数据校验实现方式,在日常的工作中已经得到了广泛的应用,希望本文能够帮助使用者更好更完善的从底层源码的角度了解Hibernate-Validator的功能,如果本文存在错误或遗漏请与作者联系,谢谢

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值