从深处去掌握数据校验@Valid的作用(级联校验)

  • 2019 年 10 月 3 日
  • 笔记

????

NBA???????????????????????

????

???Java??????????Java Bean Validation 2.0?JSR303?JSR349?JSR380?Hibernate-Validation 6.x????
???Spring??Controller????????????????Spring MVC??@Valid???JavaBean?????
???Spring?Spring?????????@Validated + MethodValidationPostProcessor???????????


?Spring????????wx??`Java??????3?`????????


??

??Bean Validation???????????????????????????????
??????Bean Validation????????????????????????????????Spring MVC?????????????????99%?????????????Spring MVC?Controller????????90%?????????@RequestBody????????JavaBean??~

???????Bean Validation??????????????????Spring????????????????????
?????????????????????????????????????????????????Spring????????~

????

?????????????????????????????????????????????????????????

@Getter  @Setter  @ToString  public class Person {      // ????message???????      @NotNull(message = "{message} -> ?????null", groups = Simple.class)      public String name;      @Max(value = 10, groups = Simple.class)      @Positive(groups = Default.class) // ??????default      public Integer age;        @NotNull(groups = Complex.class)      @NotEmpty(groups = Complex.class)      private List<@Email String> emails;      @Future(groups = Complex.class)      private Date start;        // ????? Simple??Complex?      interface Simple {      }      interface Complex {        }  }

???????

    public static void main(String[] args) {          Person person = new Person();          //person.setName("fsx");          person.setAge(18);          // email??????List??????          person.setEmails(Arrays.asList("[email protected]", "[email protected]", "aaa.com"));          //person.setStart(new Date()); //start ??????????: Sun Jul 21 10:45:03 CST 2019          //person.setStart(new Date(System.currentTimeMillis() + 10000)); //????            HibernateValidatorConfiguration configure = Validation.byProvider(HibernateValidator.class).configure();          ValidatorFactory validatorFactory = configure.failFast(false).buildValidatorFactory();          // ??validatorFactory????Validator          Validator validator = validatorFactory.getValidator();              // ???????????Default??Simple??Complex??          Set<ConstraintViolation<Person>> result = validator.validate(person, Person.Simple.class);          //Set<ConstraintViolation<Person>> result = validator.validate(person, Person.Complex.class);            // ?????????          result.stream().map(v -> v.getPropertyPath() + " " + v.getMessage() + ": " + v.getInvalidValue())                  .forEach(System.out::println);        }

?????

age ??????10: 18  name {message} -> ?????null -> ?????null: null

??????????????????Person.Simple.class??Group?????~

?????Spring MVC????????????????????????javax.validation.Valid????????????org.springframework.validation.annotation.Validated???????????????????

@Valid??

????JSR?????@Valid???????????????????????Controller?????@RequestBody??????????????????????????~

==?????????????????????????==
????????????????????????????????????????????????

???????@Valid???????????????

MetaDataProvider

???????????????????????????Provider???????????

  1. ??????????xml????????????? ??????????????
public enum ConfigurationSource {      ANNOTATION( 0 ),      XML( 1 ),      API( 2 ); //programmatic API  }
  1. MetaDataProvider???????????????
  2. ??????????????????????@Valid??????????
public interface MetaDataProvider {        // ?**??????**????Provider???  ?????????AnnotationProcessingOptionsImpl      // ????????areMemberConstraintsIgnoredFor  areReturnValueConstraintsIgnoredFor      // ??????????????~~~~~~(?????)      AnnotationProcessingOptions getAnnotationProcessingOptions();      // ??????Bean???`BeanConfiguration`   ??????null?      // BeanConfiguration??ConfigurationSource???~      <T> BeanConfiguration<? super T> getBeanConfiguration(Class<T> beanClass);    }    // ??????ConfigurationSource???Java????????????  ????????????????  // ??????????????????????  public class BeanConfiguration<T> {      // ???????      private final ConfigurationSource source;      private final Class<T> beanClass;      // ConstrainedElement??????????????????????      // ConstrainedField/ConstrainedType/ConstrainedParameter/ConstrainedExecutable        // ???ConstrainedExecutable????java.lang.reflect.Executable??      //???????java.lang.reflect.Method?Constructor      private final Set<ConstrainedElement> constrainedElements;        private final List<Class<?>> defaultGroupSequence;      private final DefaultGroupSequenceProvider<? super T> defaultGroupSequenceProvider;      ... // ?????????????????????????  }

??????
?????????
??????????????????????????????????????AnnotationMetaDataProvider

AnnotationMetaDataProvider

???????????????????Hibernate Validation???configuration source??????????@Valid???~

public class AnnotationMetaDataProvider implements MetaDataProvider {        private final ConstraintHelper constraintHelper;      private final TypeResolutionHelper typeResolutionHelper;      private final AnnotationProcessingOptions annotationProcessingOptions;      private final ValueExtractorManager valueExtractorManager;        // ???????????????????Bean  ???????Bean??~~~      private final BeanConfiguration<Object> objectBeanConfiguration;        // ??????      public AnnotationMetaDataProvider(ConstraintHelper constraintHelper,              TypeResolutionHelper typeResolutionHelper,              ValueExtractorManager valueExtractorManager,              AnnotationProcessingOptions annotationProcessingOptions) {          this.constraintHelper = constraintHelper;          this.typeResolutionHelper = typeResolutionHelper;          this.valueExtractorManager = valueExtractorManager;          this.annotationProcessingOptions = annotationProcessingOptions;            // ?????????Object?????????retrieve:??????  ????????~~~          // ????????????          this.objectBeanConfiguration = retrieveBeanConfiguration( Object.class );      }        // ??????      @Override      public AnnotationProcessingOptions getAnnotationProcessingOptions() {          return new AnnotationProcessingOptionsImpl();      }          // ????Bean?Object  ??????~~~???????  ??Object?      @Override      @SuppressWarnings("unchecked")      public <T> BeanConfiguration<T> getBeanConfiguration(Class<T> beanClass) {          if ( Object.class.equals( beanClass ) ) {              return (BeanConfiguration<T>) objectBeanConfiguration;          }          return retrieveBeanConfiguration( beanClass );      }  }

????????????retrieveBeanConfiguration()???????????????????????????????????????

  1. ValidatorFactory.getValidator()????????????????new??????????
    ?????????
  2. ??Validator.validate()??????beanMetaDataManager.getBeanMetaData( rootBeanClass )???????????metaDataProviders(??????????xml???)??????BeanConfiguration??BeanMetaDataBuilder???????????Bean?BeanMetaData???????????????
    1. ??MetaDataProvider????ClassHierarchyHelper.getHierarchy( beanClass )????????????????????????????provider.getBeanConfiguration( clazz )???????????????Object??????
    ?????????
retrieveBeanConfiguration()??

???????????Bean????????????????????ConstrainedElement??

    private <T> BeanConfiguration<T> retrieveBeanConfiguration(Class<T> beanClass) {          // ????????clazz.getDeclaredFields()  ?????????????????  ??private??  ????????????          Set<ConstrainedElement> constrainedElements = getFieldMetaData( beanClass );          constrainedElements.addAll( getMethodMetaData( beanClass ) );          constrainedElements.addAll( getConstructorMetaData( beanClass ) );            //TODO GM: currently class level constraints are represented by a PropertyMetaData. This          //works but seems somewhat unnatural          // ??TODO?????????????PropertyMetadata?????????????????          // ReturnValueMetaData?ExecutableMetaData?ParameterMetaData?PropertyMetaData            // ???????????????????????set??????????          Set<MetaConstraint<?>> classLevelConstraints = getClassLevelConstraints( beanClass );          if (!classLevelConstraints.isEmpty()) {              ConstrainedType classLevelMetaData = new ConstrainedType(ConfigurationSource.ANNOTATION, beanClass, classLevelConstraints);              constrainedElements.add(classLevelMetaData);          }            // ?????BeanConfiguration??          return new BeanConfiguration<>(ConfigurationSource.ANNOTATION, beanClass,                  constrainedElements,                  getDefaultGroupSequence( beanClass ),  //????????@GroupSequence??                  getDefaultGroupSequenceProvider( beanClass ) // ????????@GroupSequenceProvider??          );      }

??????Bean???????????????????????????Demo??Person?????????BeanConfiguration???????
?????????
?????????
?????????????????????????????????

??????????????????????????????????????????????????????ConstrainedElement.getConstraints()???~

????????????????????????????????????????????????????????????

??Field?getFieldMetaData( beanClass )
  1. ????????Field?clazz.getDeclaredFields()
  2. ???Field????ConstrainedElement????~~~
    1. ????????????Field???????????
??Method?getMethodMetaData( beanClass )
  1. ?????????Method?clazz.getDeclaredMethods()
  2. ??????????(isSynthetic)??
  3. ???Method??????ConstrainedExecutable??~~(ConstrainedExecutable???ConstrainedElement)????????????????????????????????????
    1. ??????????????
    2. ????????????????????????????

    ??Constructor?getConstructorMetaData( beanClass )

    ?????Method??

    ??Type?getClassLevelConstraints( beanClass )
  4. ??????????????????ConstraintDescriptor
  5. ???????ConstraintDescriptor??????????Set<MetaConstraint<?>>????
    1.
  6. ?Set<MetaConstraint<?>>???ConstrainedType?????ConstrainedType??ConstrainedElement?

==?????????????????Type?????????????????????==
??????????@Valid???????

    // type??????N???      // Field??.getGenericType() // ?????      // Method??.getGenericReturnType() // ?????      // Constructor?.getDeclaringClass() // ??????        // annotatedElement???????????????????????????????????      private CascadingMetaDataBuilder getCascadingMetaData(Type type, AnnotatedElement annotatedElement, Map<TypeVariable<?>, CascadingMetaDataBuilder> containerElementTypesCascadingMetaData) {          return CascadingMetaDataBuilder.annotatedObject( type, annotatedElement.isAnnotationPresent( Valid.class ), containerElementTypesCascadingMetaData, getGroupConversions( annotatedElement ) );      }

???????????????????annotatedElement.isAnnotationPresent(Valid.class)???????????????????????????????????JSR??@Valid???~

Spring????????????Spring??????~

ConstraintValidator.isValid()???

????????????????????ConstraintValidator.isValid()?????????????(??)?????(???)?

public abstract class ConstraintTree<A extends Annotation> {      ...      protected final <T, V> Set<ConstraintViolation<T>> validateSingleConstraint(ValidationContext<T> executionContext,              ValueContext<?, ?> valueContext,              ConstraintValidatorContextImpl constraintValidatorContext,              ConstraintValidator<A, V> validator) {          ...          V validatedValue = (V) valueContext.getCurrentValidatedValue();          isValid = validator.isValid( validatedValue, constraintValidatorContext );          ...          // ??????????????  ???????          if ( !isValid ) {              return executionContext.createConstraintViolations(valueContext, constraintValidatorContext);          }          return Collections.emptySet();      }      ...  }

??????????????Group???

success = metaConstraint.validateConstraint( validationContext, valueContext );

MetaConstraint????????????????????ConstrainedElement.getConstraints??????????????????

// ConstraintTree<A>  boolean validationResult = constraintTree.validateConstraints( executionContext, valueContext );

so????????isValid????????????

==??????????????????show????==

Demo Show

?????????Person??JavaBean???????????????????Field????????????Bean Validation?????????????????????????????

????Field

?

??Method??????

??Constructor??????

??????????????

?????????????????????????????????Spring??Controller????????????????Spring MVC??@Valid???JavaBean?????

????

?????????????????????????????????????????????????????????Person???????Child???????????Person??????????Child???????

@Getter  @Setter  @ToString  public class Person {        @NotNull      private String name;      @NotNull      @Positive      private Integer age;      @Valid      @NotNull      private InnerChild child;        @Getter      @Setter      @ToString      public static class InnerChild {          @NotNull          private String name;          @NotNull          @Positive          private Integer age;      }    }

???????

    public static void main(String[] args) {          Person person = new Person();          person.setName("fsx");          Person.InnerChild child = new Person.InnerChild();          child.setName("fsx-son");          child.setAge(-1);          person.setChild(child); // ???            Validator validator = Validation.byProvider(HibernateValidator.class).configure().failFast(false)                  .buildValidatorFactory().getValidator();          Set<ConstraintViolation<Person>> result = validator.validate(person);            // ??????          result.stream().map(v -> v.getPropertyPath() + " " + v.getMessage() + ": " + v.getInvalidValue())                  .forEach(System.out::println);      }

???

child.age ?????: -1  age ???null: null

?child.age??????????~

??

???????????????Bean Validation??????????????????????????Spring??????????~

????

????????????????-????-????-????-????

==The last????????????????????????????????????????????????~==

?????????????wx????Java??????3??
??????????wx??fsx641385712???????wx??????????"java??" ??????????