As of Bean Validation 1.1, constraints can not only be applied to JavaBeans and their properties, but also to the parameters and return values of the methods and constructors of any Java type. That way Jakarta Bean Validation constraints can be used to specify
@Override @Nullable public Object invoke(MethodInvocation invocation)throws Throwable { // Avoid Validator invocation on FactoryBean.getObjectType/isSingleton if (isFactoryBeanMetadataMethod(invocation.getMethod())) { return invocation.proceed(); }
Class<?>[] groups = determineValidationGroups(invocation);
// Standard Bean Validation 1.1 API ExecutableValidator execVal = this.validator.forExecutables(); Method methodToValidate = invocation.getMethod(); Set<ConstraintViolation<Object>> result;
Object target = invocation.getThis(); Assert.state(target != null, "Target must not be null");
try { result = execVal.validateParameters(target, methodToValidate, invocation.getArguments(), groups); } catch (IllegalArgumentException ex) { // Probably a generic type mismatch between interface and impl as reported in SPR-12237 / HV-1011 // Let's try to find the bridged method on the implementation class... methodToValidate = BridgeMethodResolver.findBridgedMethod( ClassUtils.getMostSpecificMethod(invocation.getMethod(), target.getClass())); result = execVal.validateParameters(target, methodToValidate, invocation.getArguments(), groups); } if (!result.isEmpty()) { thrownew ConstraintViolationException(result); }
Object returnValue = invocation.proceed();
result = execVal.validateReturnValue(target, methodToValidate, returnValue, groups); if (!result.isEmpty()) { thrownew ConstraintViolationException(result); }
// Standard Bean Validation 1.1 API ExecutableValidator execVal = this.validator.forExecutables(); Set<ConstraintViolation<Object>> result;
Object[] arguments = invocation.getArguments();
//validateParameters try { result = execVal.validateParameters(target, methodToValidate, arguments, groups); } catch (IllegalArgumentException | ConstraintDeclarationException ex) { // Probably a generic type mismatch between interface and impl as reported in SPR-12237 / HV-1011 // Let's try to find the bridged method on the implementation class... methodToValidate = BridgeMethodResolver.findBridgedMethod( ClassUtils.getMostSpecificMethod(invocation.getMethod(), target.getClass()));
result = execVal.validateParameters(target, methodToValidate, arguments, groups); } if (!result.isEmpty()) { violationHandler.handle(result); }
//Parameter object Parameter[] parameters = methodToValidate.getParameters(); for (int i = 0; i < parameters.length; i++) { if (parameters[i].isAnnotationPresent(Valid.class)) { result = validator.validate(arguments[i], groups); if (!result.isEmpty()) { violationHandler.handle(result); } } }
Object returnValue = invocation.proceed();
result = execVal.validateReturnValue(target, methodToValidate, returnValue, groups); if (!result.isEmpty()) { violationHandler.handle(result); }
Resolves method arguments annotated with @RequestBody and handles return values from methods annotated with @ResponseBody by reading and writing to the body of the request or response with an HttpMessageConverter. An @RequestBody method argument is also validated ifitis annotated with @javax.validation.Valid. In caseof validation failure, MethodArgumentNotValidException is raised and results in an HTTP 400 response status code if DefaultHandlerExceptionResolver is configured.
/** * Determine any validation hints by the given annotation. * <p>This implementation checks for {@code@javax.validation.Valid}, * Spring's {@link org.springframework.validation.annotation.Validated}, * and custom annotations whose name starts with "Valid". * @param ann the annotation (potentially a validation annotation) * @return the validation hints to apply (possibly an empty array), * or {@code null} if this annotation does not trigger any validation */ @Nullable publicstatic Object[] determineValidationHints(Annotation ann) { Class<? extends Annotation> annotationType = ann.annotationType(); String annotationName = annotationType.getName(); if ("javax.validation.Valid".equals(annotationName)) { return EMPTY_OBJECT_ARRAY; } Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class); if (validatedAnn != null) { Object hints = validatedAnn.value(); return convertValidationHints(hints); } if (annotationType.getSimpleName().startsWith("Valid")) { Object hints = AnnotationUtils.getValue(ann); return convertValidationHints(hints); } returnnull; }
问题来了呀
第23行,竟然用了个startsWith!!!
这个方法上虽然注明了这点custom annotations whose name starts with "Valid",但是很坑呀,于是我提了个issue
issue - AbstractMessageConverterMethodArgumentResolver#validateIfApplicable do more than expected