Add ~.validation.method package

Extract classes from ~.validation.beanvalidation without a direct
dependency on beanvalidation.

See gh-30644
This commit is contained in:
rstoyanchev 2023-07-03 15:05:32 +01:00
parent 0da2241367
commit 592ab0f350
27 changed files with 220 additions and 120 deletions

View File

@ -18,7 +18,6 @@ package org.springframework.validation.beanvalidation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedHashMap;
@ -50,7 +49,6 @@ import org.springframework.core.MethodParameter;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.function.SingletonSupplier;
import org.springframework.validation.BeanPropertyBindingResult;
@ -59,6 +57,10 @@ import org.springframework.validation.DefaultMessageCodesResolver;
import org.springframework.validation.Errors;
import org.springframework.validation.MessageCodesResolver;
import org.springframework.validation.annotation.Validated;
import org.springframework.validation.method.MethodValidationResult;
import org.springframework.validation.method.MethodValidator;
import org.springframework.validation.method.ParameterErrors;
import org.springframework.validation.method.ParameterValidationResult;
/**
* {@link MethodValidator} that uses a Bean Validation
@ -70,12 +72,12 @@ import org.springframework.validation.annotation.Validated;
*/
public class MethodValidationAdapter implements MethodValidator {
private static final MethodValidationResult emptyValidationResult = MethodValidationResult.emptyResult();
private static final ObjectNameResolver defaultObjectNameResolver = new DefaultObjectNameResolver();
private static final Comparator<ParameterValidationResult> resultComparator = new ResultComparator();
private static final MethodValidationResult emptyResult = new EmptyMethodValidationResult();
private final Supplier<Validator> validator;
@ -219,7 +221,7 @@ public class MethodValidationAdapter implements MethodValidator {
invokeValidatorForArguments(target, method, arguments, groups);
if (violations.isEmpty()) {
return emptyResult;
return emptyValidationResult;
}
return adaptViolations(target, method, violations,
@ -257,7 +259,7 @@ public class MethodValidationAdapter implements MethodValidator {
invokeValidatorForReturnValue(target, method, returnValue, groups);
if (violations.isEmpty()) {
return emptyResult;
return emptyValidationResult;
}
return adaptViolations(target, method, violations,
@ -320,7 +322,7 @@ public class MethodValidationAdapter implements MethodValidator {
cascadedViolations.forEach((node, builder) -> validatonResultList.add(builder.build()));
validatonResultList.sort(resultComparator);
return new DefaultMethodValidationResult(target, method, validatonResultList);
return MethodValidationResult.create(target, method, validatonResultList);
}
private MethodParameter initMethodParameter(Method method, int index) {
@ -534,91 +536,4 @@ public class MethodValidationAdapter implements MethodValidator {
}
}
/**
* Default {@link MethodValidationResult} implementation with non-zero errors.
*/
private static class DefaultMethodValidationResult implements MethodValidationResult {
private final Object target;
private final Method method;
private final List<ParameterValidationResult> allValidationResults;
private final boolean forReturnValue;
DefaultMethodValidationResult(Object target, Method method, List<ParameterValidationResult> results) {
Assert.notEmpty(results, "'results' is required and must not be empty");
Assert.notNull(target, "'target' is required");
Assert.notNull(method, "Method is required");
this.target = target;
this.method = method;
this.allValidationResults = results;
this.forReturnValue = (results.get(0).getMethodParameter().getParameterIndex() == -1);
}
@Override
public Object getTarget() {
return this.target;
}
@Override
public Method getMethod() {
return this.method;
}
@Override
public boolean isForReturnValue() {
return this.forReturnValue;
}
@Override
public List<ParameterValidationResult> getAllValidationResults() {
return this.allValidationResults;
}
@Override
public String toString() {
return getAllErrors().size() + " validation errors " +
"for " + (isForReturnValue() ? "return value" : "arguments") + " of " +
this.method.toGenericString();
}
}
/**
* {@link MethodValidationResult} for when there are no errors.
*/
private static class EmptyMethodValidationResult implements MethodValidationResult {
@Override
public Object getTarget() {
throw new UnsupportedOperationException();
}
@Override
public Method getMethod() {
throw new UnsupportedOperationException();
}
@Override
public boolean isForReturnValue() {
throw new UnsupportedOperationException();
}
@Override
public List<ParameterValidationResult> getAllValidationResults() {
return Collections.emptyList();
}
@Override
public String toString() {
return "0 validation errors";
}
}
}

View File

@ -34,6 +34,8 @@ import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.validation.method.MethodValidationException;
import org.springframework.validation.method.MethodValidationResult;
/**
* An AOP Alliance {@link MethodInterceptor} implementation that delegates to a

View File

@ -36,6 +36,8 @@ import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.util.Assert;
import org.springframework.util.function.SingletonSupplier;
import org.springframework.validation.annotation.Validated;
import org.springframework.validation.method.MethodValidationException;
import org.springframework.validation.method.MethodValidationResult;
/**
* A convenient {@link BeanPostProcessor} implementation that delegates to a

View File

@ -0,0 +1,80 @@
/*
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.validation.method;
import java.lang.reflect.Method;
import java.util.List;
import org.springframework.util.Assert;
/**
* Default {@link MethodValidationResult} implementation as a simple container.
*
* @author Rossen Stoyanchev
* @since 6.1
*/
final class DefaultMethodValidationResult implements MethodValidationResult {
private final Object target;
private final Method method;
private final List<ParameterValidationResult> allValidationResults;
private final boolean forReturnValue;
DefaultMethodValidationResult(Object target, Method method, List<ParameterValidationResult> results) {
Assert.notEmpty(results, "'results' is required and must not be empty");
Assert.notNull(target, "'target' is required");
Assert.notNull(method, "Method is required");
this.target = target;
this.method = method;
this.allValidationResults = results;
this.forReturnValue = (results.get(0).getMethodParameter().getParameterIndex() == -1);
}
@Override
public Object getTarget() {
return this.target;
}
@Override
public Method getMethod() {
return this.method;
}
@Override
public boolean isForReturnValue() {
return this.forReturnValue;
}
@Override
public List<ParameterValidationResult> getAllValidationResults() {
return this.allValidationResults;
}
@Override
public String toString() {
return getAllErrors().size() + " validation errors " +
"for " + (isForReturnValue() ? "return value" : "arguments") + " of " +
this.method.toGenericString();
}
}

View File

@ -0,0 +1,56 @@
/*
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.validation.method;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.List;
/**
* {@link MethodValidationResult} with an empty list of results.
*
* @author Rossen Stoyanchev
* @since 6.1
*/
final class EmptyMethodValidationResult implements MethodValidationResult {
@Override
public Object getTarget() {
throw new UnsupportedOperationException();
}
@Override
public Method getMethod() {
throw new UnsupportedOperationException();
}
@Override
public boolean isForReturnValue() {
throw new UnsupportedOperationException();
}
@Override
public List<ParameterValidationResult> getAllValidationResults() {
return Collections.emptyList();
}
@Override
public String toString() {
return "0 validation errors";
}
}

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.validation.beanvalidation;
package org.springframework.validation.method;
import java.lang.reflect.Method;
import java.util.List;

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.validation.beanvalidation;
package org.springframework.validation.method;
import java.lang.reflect.Method;
import java.util.List;
@ -101,4 +101,25 @@ public interface MethodValidationResult {
.toList();
}
/**
* Factory method to create a {@link MethodValidationResult} instance.
* @param target the target Object
* @param method the target method
* @param results method validation results, expected to be non-empty
* @return the created instance
*/
static MethodValidationResult create(Object target, Method method, List<ParameterValidationResult> results) {
return new DefaultMethodValidationResult(target, method, results);
}
/**
* Factory method to create a {@link MethodValidationResult} instance with
* 0 errors, suitable to use as a constant. Getters for a target object or
* method are not supported.
*/
static MethodValidationResult emptyResult() {
return new EmptyMethodValidationResult();
}
}

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.validation.beanvalidation;
package org.springframework.validation.method;
import java.lang.reflect.Method;

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.validation.beanvalidation;
package org.springframework.validation.method;
import java.util.List;

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.validation.beanvalidation;
package org.springframework.validation.method;
import java.util.Collection;
import java.util.List;

View File

@ -0,0 +1,21 @@
/**
* Abstractions and support classes for method validation, independent of the
* underlying validation library.
*
* <p>The main abstractions:
* <ul>
* <li>{@link org.springframework.validation.method.MethodValidator} to apply
* method validation, and return or handle the results.
* <li>{@link org.springframework.validation.method.MethodValidationResult} and
* related types to represent the results.
* <li>{@link org.springframework.validation.method.MethodValidationException}
* to expose method validation results.
* </ul>
*/
@NonNullApi
@NonNullFields
package org.springframework.validation.method;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;

View File

@ -33,6 +33,9 @@ import org.springframework.context.MessageSourceResolvable;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
import org.springframework.validation.FieldError;
import org.springframework.validation.method.MethodValidationResult;
import org.springframework.validation.method.ParameterErrors;
import org.springframework.validation.method.ParameterValidationResult;
import static org.assertj.core.api.Assertions.assertThat;

View File

@ -22,8 +22,8 @@ import java.util.Locale;
import org.springframework.context.MessageSource;
import org.springframework.http.HttpStatus;
import org.springframework.validation.beanvalidation.MethodValidationResult;
import org.springframework.validation.beanvalidation.ParameterValidationResult;
import org.springframework.validation.method.MethodValidationResult;
import org.springframework.validation.method.ParameterValidationResult;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.util.BindErrorUtils;

View File

@ -27,16 +27,16 @@ import org.springframework.lang.Nullable;
import org.springframework.validation.BindingResult;
import org.springframework.validation.MessageCodesResolver;
import org.springframework.validation.beanvalidation.MethodValidationAdapter;
import org.springframework.validation.beanvalidation.MethodValidationResult;
import org.springframework.validation.beanvalidation.MethodValidator;
import org.springframework.validation.beanvalidation.ParameterErrors;
import org.springframework.validation.method.MethodValidationResult;
import org.springframework.validation.method.MethodValidator;
import org.springframework.validation.method.ParameterErrors;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
import org.springframework.web.bind.support.WebBindingInitializer;
/**
* {@link org.springframework.validation.beanvalidation.MethodValidator} that
* {@link MethodValidator} that
* uses Bean Validation to validate {@code @RequestMapping} method arguments.
*
* <p>Handles validation results by populating {@link BindingResult} method

View File

@ -36,7 +36,7 @@ import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.validation.beanvalidation.MethodValidator;
import org.springframework.validation.method.MethodValidator;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.bind.support.WebDataBinderFactory;

View File

@ -36,7 +36,7 @@ import org.springframework.lang.Nullable;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.BindingResult;
import org.springframework.validation.beanvalidation.MethodValidationResult;
import org.springframework.validation.method.MethodValidationResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingMatrixVariableException;
import org.springframework.web.bind.MissingPathVariableException;

View File

@ -44,7 +44,7 @@ import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.validation.beanvalidation.MethodValidator;
import org.springframework.validation.method.MethodValidator;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.reactive.BindingContext;
import org.springframework.web.reactive.HandlerResult;

View File

@ -39,7 +39,7 @@ import org.springframework.http.codec.HttpMessageReader;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils.MethodFilter;
import org.springframework.validation.beanvalidation.MethodValidator;
import org.springframework.validation.method.MethodValidator;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;

View File

@ -35,7 +35,7 @@ import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.beanvalidation.MethodValidator;
import org.springframework.validation.method.MethodValidator;
import org.springframework.web.bind.support.WebBindingInitializer;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.method.annotation.HandlerMethodValidator;

View File

@ -30,7 +30,7 @@ import org.springframework.http.HttpStatusCode;
import org.springframework.http.ProblemDetail;
import org.springframework.http.ResponseEntity;
import org.springframework.lang.Nullable;
import org.springframework.validation.beanvalidation.MethodValidationException;
import org.springframework.validation.method.MethodValidationException;
import org.springframework.web.ErrorResponse;
import org.springframework.web.ErrorResponseException;
import org.springframework.web.bind.annotation.ControllerAdvice;

View File

@ -43,7 +43,7 @@ import org.springframework.validation.FieldError;
import org.springframework.validation.Validator;
import org.springframework.validation.annotation.Validated;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.validation.beanvalidation.ParameterValidationResult;
import org.springframework.validation.method.ParameterValidationResult;
import org.springframework.validation.beanvalidation.SpringValidatorAdapter;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;

View File

@ -37,8 +37,8 @@ import org.springframework.http.ProblemDetail;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.beanvalidation.MethodValidationException;
import org.springframework.validation.beanvalidation.MethodValidationResult;
import org.springframework.validation.method.MethodValidationException;
import org.springframework.validation.method.MethodValidationResult;
import org.springframework.web.ErrorResponse;
import org.springframework.web.ErrorResponseException;
import org.springframework.web.bind.support.WebExchangeBindException;

View File

@ -51,7 +51,7 @@ import org.springframework.ui.ModelMap;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ReflectionUtils.MethodFilter;
import org.springframework.validation.beanvalidation.MethodValidator;
import org.springframework.validation.method.MethodValidator;
import org.springframework.web.accept.ContentNegotiationManager;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;

View File

@ -34,7 +34,7 @@ import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.lang.Nullable;
import org.springframework.validation.BindException;
import org.springframework.validation.beanvalidation.MethodValidationException;
import org.springframework.validation.method.MethodValidationException;
import org.springframework.web.ErrorResponse;
import org.springframework.web.ErrorResponseException;
import org.springframework.web.HttpMediaTypeNotAcceptableException;

View File

@ -33,7 +33,7 @@ import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.lang.Nullable;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.beanvalidation.MethodValidationException;
import org.springframework.validation.method.MethodValidationException;
import org.springframework.web.ErrorResponse;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpMediaTypeNotSupportedException;

View File

@ -39,7 +39,7 @@ import org.springframework.validation.FieldError;
import org.springframework.validation.Validator;
import org.springframework.validation.annotation.Validated;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.validation.beanvalidation.ParameterValidationResult;
import org.springframework.validation.method.ParameterValidationResult;
import org.springframework.validation.beanvalidation.SpringValidatorAdapter;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.WebDataBinder;

View File

@ -43,8 +43,8 @@ import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindException;
import org.springframework.validation.MapBindingResult;
import org.springframework.validation.beanvalidation.MethodValidationException;
import org.springframework.validation.beanvalidation.MethodValidationResult;
import org.springframework.validation.method.MethodValidationException;
import org.springframework.validation.method.MethodValidationResult;
import org.springframework.web.ErrorResponse;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpMediaTypeNotSupportedException;