从深处去掌握数据校验@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???????????
??
??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
???????????
- ??????????xml????????????? ??????????????
public enum ConfigurationSource { ANNOTATION( 0 ), XML( 1 ), API( 2 ); //programmatic API }
MetaDataProvider
???????????????- ?????????????????
?????@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()
???????????????????????????????????????
ValidatorFactory.getValidator()
????????????????new
??????????
- ??
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 )
- ????????
Field
?clazz.getDeclaredFields()
- ???
Field
????ConstrainedElement
????~~~
1. ????????????Field
???????????
??Method?getMethodMetaData( beanClass )
- ?????????
Method
?clazz.getDeclaredMethods()
- ??????????(isSynthetic)??
-
???Method??????
ConstrainedExecutable
??~~(ConstrainedExecutable
???ConstrainedElement
)????????????????????????????????????
1. ??????????????
2. ??????????????????????????????Constructor?getConstructorMetaData( beanClass )
?????Method??
??Type?getClassLevelConstraints( beanClass )
- ??????????????????
ConstraintDescriptor
- ???????
ConstraintDescriptor
??????????Set<MetaConstraint<?>>
????
1. -
?
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??"
??????????