Provide access to underlying ConstraintViolation
Closes gh-33025
This commit is contained in:
@@ -50,6 +50,7 @@ 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.function.SingletonSupplier;
|
||||
import org.springframework.validation.BeanPropertyBindingResult;
|
||||
import org.springframework.validation.BindingResult;
|
||||
@@ -402,7 +403,7 @@ public class MethodValidationAdapter implements MethodValidator {
|
||||
String[] codes = this.messageCodesResolver.resolveMessageCodes(code, objectName, paramName, parameterType);
|
||||
Object[] arguments = this.validatorAdapter.get().getArgumentsForConstraint(objectName, paramName, descriptor);
|
||||
|
||||
return new DefaultMessageSourceResolvable(codes, arguments, violation.getMessage());
|
||||
return new ViolationMessageSourceResolvable(codes, arguments, violation.getMessage(), violation);
|
||||
}
|
||||
|
||||
private BindingResult createBindingResult(MethodParameter parameter, @Nullable Object argument) {
|
||||
@@ -472,7 +473,11 @@ public class MethodValidationAdapter implements MethodValidator {
|
||||
public ParameterValidationResult build() {
|
||||
return new ParameterValidationResult(
|
||||
this.parameter, this.value, this.resolvableErrors, this.container,
|
||||
this.containerIndex, this.containerKey);
|
||||
this.containerIndex, this.containerKey,
|
||||
(error, sourceType) -> {
|
||||
Assert.isTrue(sourceType.equals(ConstraintViolation.class), "Unexpected source type");
|
||||
return ((ViolationMessageSourceResolvable) error).getViolation();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -526,6 +531,24 @@ public class MethodValidationAdapter implements MethodValidator {
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static class ViolationMessageSourceResolvable extends DefaultMessageSourceResolvable {
|
||||
|
||||
private final transient ConstraintViolation<Object> violation;
|
||||
|
||||
public ViolationMessageSourceResolvable(
|
||||
String[] codes, Object[] arguments, String defaultMessage, ConstraintViolation<Object> violation) {
|
||||
|
||||
super(codes, arguments, defaultMessage);
|
||||
this.violation = violation;
|
||||
}
|
||||
|
||||
public ConstraintViolation<Object> getViolation() {
|
||||
return this.violation;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Default algorithm to select an object name, as described in {@link #setObjectNameResolver}.
|
||||
*/
|
||||
|
||||
@@ -47,7 +47,9 @@ public class ParameterErrors extends ParameterValidationResult implements Errors
|
||||
MethodParameter parameter, @Nullable Object argument, Errors errors,
|
||||
@Nullable Object container, @Nullable Integer index, @Nullable Object key) {
|
||||
|
||||
super(parameter, argument, errors.getAllErrors(), container, index, key);
|
||||
super(parameter, argument, errors.getAllErrors(),
|
||||
container, index, key, (error, sourceType) -> ((FieldError) error).unwrap(sourceType));
|
||||
|
||||
this.errors = errors;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@ package org.springframework.validation.method;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.springframework.context.MessageSourceResolvable;
|
||||
import org.springframework.core.MethodParameter;
|
||||
@@ -62,13 +64,16 @@ public class ParameterValidationResult {
|
||||
@Nullable
|
||||
private final Object containerKey;
|
||||
|
||||
private final BiFunction<MessageSourceResolvable, Class<?>, Object> sourceLookup;
|
||||
|
||||
|
||||
/**
|
||||
* Create a {@code ParameterValidationResult}.
|
||||
*/
|
||||
public ParameterValidationResult(
|
||||
MethodParameter param, @Nullable Object arg, Collection<? extends MessageSourceResolvable> errors,
|
||||
@Nullable Object container, @Nullable Integer index, @Nullable Object key) {
|
||||
@Nullable Object container, @Nullable Integer index, @Nullable Object key,
|
||||
BiFunction<MessageSourceResolvable, Class<?>, Object> sourceLookup) {
|
||||
|
||||
Assert.notNull(param, "MethodParameter is required");
|
||||
Assert.notEmpty(errors, "`resolvableErrors` must not be empty");
|
||||
@@ -78,18 +83,36 @@ public class ParameterValidationResult {
|
||||
this.container = container;
|
||||
this.containerIndex = index;
|
||||
this.containerKey = key;
|
||||
this.sourceLookup = sourceLookup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@code ParameterValidationResult}.
|
||||
* @deprecated in favor of
|
||||
* {@link ParameterValidationResult#ParameterValidationResult(MethodParameter, Object, Collection, Object, Integer, Object)}
|
||||
* {@link ParameterValidationResult#ParameterValidationResult(MethodParameter, Object, Collection, Object, Integer, Object, Function)}
|
||||
*/
|
||||
@Deprecated(since = "6.2", forRemoval = true)
|
||||
public ParameterValidationResult(
|
||||
MethodParameter param, @Nullable Object arg, Collection<? extends MessageSourceResolvable> errors,
|
||||
@Nullable Object container, @Nullable Integer index, @Nullable Object key) {
|
||||
|
||||
this(param, arg, errors, container, index, key, (error, sourceType) -> {
|
||||
throw new IllegalArgumentException("No source object of the given type");
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@code ParameterValidationResult}.
|
||||
* @deprecated in favor of
|
||||
* {@link ParameterValidationResult#ParameterValidationResult(MethodParameter, Object, Collection, Object, Integer, Object, Function)}
|
||||
*/
|
||||
@Deprecated(since = "6.1.3", forRemoval = true)
|
||||
public ParameterValidationResult(
|
||||
MethodParameter param, @Nullable Object arg, Collection<? extends MessageSourceResolvable> errors) {
|
||||
|
||||
this(param, arg, errors, null, null, null);
|
||||
this(param, arg, errors, null, null, null, (error, sourceType) -> {
|
||||
throw new IllegalArgumentException("No source object of the given type");
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -164,6 +187,17 @@ public class ParameterValidationResult {
|
||||
return this.containerKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unwrap the source behind the given error. For Jakarta Bean validation the
|
||||
* source is a {@link jakarta.validation.ConstraintViolation}.
|
||||
* @param sourceType the expected source type
|
||||
* @return the source object of the given type
|
||||
* @since 6.2
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T unwrap(MessageSourceResolvable error, Class<T> sourceType) {
|
||||
return (T) this.sourceLookup.apply(error, sourceType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object other) {
|
||||
|
||||
Reference in New Issue
Block a user