diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/AnnotatedControllerConfigurer.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/AnnotatedControllerConfigurer.java index da700d77..575317e3 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/AnnotatedControllerConfigurer.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/AnnotatedControllerConfigurer.java @@ -27,6 +27,7 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.Executor; +import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.stream.Collectors; @@ -492,7 +493,7 @@ public class AnnotatedControllerConfigurer private final HandlerMethodArgumentResolverComposite argumentResolvers; @Nullable - private final Consumer methodValidationHelper; + private final BiConsumer methodValidationHelper; @Nullable private final Executor executor; diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/DataFetcherHandlerMethod.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/DataFetcherHandlerMethod.java index 6795e842..89d35a0d 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/DataFetcherHandlerMethod.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/DataFetcherHandlerMethod.java @@ -17,7 +17,7 @@ package org.springframework.graphql.data.method.annotation.support; import java.util.Arrays; import java.util.concurrent.Executor; -import java.util.function.Consumer; +import java.util.function.BiConsumer; import graphql.schema.DataFetchingEnvironment; import org.reactivestreams.Publisher; @@ -50,7 +50,7 @@ public class DataFetcherHandlerMethod extends InvocableHandlerMethodSupport { private final HandlerMethodArgumentResolverComposite resolvers; - private final Consumer validationHelper; + private final BiConsumer validationHelper; private final ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer(); @@ -66,12 +66,13 @@ public class DataFetcherHandlerMethod extends InvocableHandlerMethodSupport { */ public DataFetcherHandlerMethod( HandlerMethod handlerMethod, HandlerMethodArgumentResolverComposite resolvers, - @Nullable Consumer validationHelper, @Nullable Executor executor, boolean subscription) { + @Nullable BiConsumer validationHelper, @Nullable Executor executor, + boolean subscription) { super(handlerMethod, executor); Assert.isTrue(!resolvers.getResolvers().isEmpty(), "No argument resolvers"); this.resolvers = resolvers; - this.validationHelper = (validationHelper != null ? validationHelper : args -> {}); + this.validationHelper = (validationHelper != null ? validationHelper : (controller, args) -> {}); this.subscription = subscription; } @@ -179,7 +180,7 @@ public class DataFetcherHandlerMethod extends InvocableHandlerMethodSupport { @Nullable private Object validateAndInvoke(Object[] args, DataFetchingEnvironment environment) { - this.validationHelper.accept(args); + this.validationHelper.accept(getBean(), args); return doInvoke(environment.getGraphQlContext(), args); } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ValidationHelper.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ValidationHelper.java index a0f5d06d..73f46637 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ValidationHelper.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ValidationHelper.java @@ -16,8 +16,9 @@ package org.springframework.graphql.data.method.annotation.support; import java.lang.annotation.Annotation; +import java.lang.reflect.Method; import java.util.Set; -import java.util.function.Consumer; +import java.util.function.BiConsumer; import jakarta.validation.Constraint; import jakarta.validation.ConstraintViolation; @@ -61,7 +62,7 @@ class ValidationHelper { * {@link Validated}, {@link Valid}, or {@link Constraint} annotations. */ @Nullable - public Consumer getValidationHelperFor(HandlerMethod handlerMethod) { + public BiConsumer getValidationHelperFor(HandlerMethod handlerMethod) { boolean requiresMethodValidation = false; Class[] methodValidationGroups = null; @@ -75,7 +76,7 @@ class ValidationHelper { requiresMethodValidation = true; } - Consumer parameterValidator = null; + BiConsumer parameterValidator = null; MethodParameter[] parameters = handlerMethod.getMethodParameters(); for (int i = 0; i < parameters.length; i++) { @@ -94,7 +95,7 @@ class ValidationHelper { } } - Consumer result = (requiresMethodValidation ? + BiConsumer result = (requiresMethodValidation ? new HandlerMethodValidator(handlerMethod, methodValidationGroups) : null); if (parameterValidator != null) { @@ -141,24 +142,24 @@ class ValidationHelper { /** * Callback to apply validation to the invocation of a {@link HandlerMethod}. */ - private class HandlerMethodValidator implements Consumer { + private class HandlerMethodValidator implements BiConsumer { - private final HandlerMethod handlerMethod; + private final Method method; private final Class[] validationGroups; HandlerMethodValidator(HandlerMethod handlerMethod, @Nullable Class[] validationGroups) { Assert.notNull(handlerMethod, "HandlerMethod is required"); - this.handlerMethod = handlerMethod; + this.method = handlerMethod.getMethod(); this.validationGroups = (validationGroups != null ? validationGroups : new Class[] {}); } @Override - public void accept(Object[] arguments) { + public void accept(Object controller, Object[] arguments) { Set> violations = - ValidationHelper.this.validator.forExecutables().validateParameters( - this.handlerMethod.getBean(), this.handlerMethod.getMethod(), arguments, this.validationGroups); + ValidationHelper.this.validator.forExecutables() + .validateParameters(controller, this.method, arguments, this.validationGroups); if (!violations.isEmpty()) { throw new ConstraintViolationException(violations); @@ -172,7 +173,7 @@ class ValidationHelper { * because it's annotated with Spring's {@code @Validated} rather than with * {@code @Valid}. */ - private class MethodParameterValidator implements Consumer { + private class MethodParameterValidator implements BiConsumer { private final int index; @@ -184,7 +185,7 @@ class ValidationHelper { } @Override - public void accept(Object[] arguments) { + public void accept(Object controller, Object[] arguments) { Set> violations = ValidationHelper.this.validator.validate(arguments[this.index], this.validationGroups); diff --git a/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/ValidationHelperTests.java b/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/ValidationHelperTests.java index dd841e9e..d8fcde93 100644 --- a/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/ValidationHelperTests.java +++ b/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/ValidationHelperTests.java @@ -20,7 +20,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.reflect.Method; import java.util.Arrays; -import java.util.function.Consumer; +import java.util.function.BiConsumer; import jakarta.validation.ConstraintViolation; import jakarta.validation.ConstraintViolationException; @@ -54,45 +54,49 @@ class ValidationHelperTests { @Test void shouldIgnoreMethodsWithoutAnnotations() { - Consumer validator = createValidator(MyBean.class, "notValidatedMethod"); + BiConsumer validator = createValidator(MyBean.class, "notValidatedMethod"); assertThat(validator).isNull(); } @Test void shouldRaiseValidationErrorForAnnotatedParams() { - Consumer validator1 = createValidator(MyBean.class, "myValidMethod"); - assertViolation(() -> validator1.accept(new Object[] {null, 2}), "myValidMethod.arg0"); - assertViolation(() -> validator1.accept(new Object[] {"test", 12}), "myValidMethod.arg1"); + MyBean bean = new MyBean(); - Consumer validator2 = createValidator(MyBean.class, "myValidatedParameterMethod"); - assertViolation(() -> validator2.accept(new Object[] {new ConstrainedInput(100)}), "integerValue"); + BiConsumer validator1 = createValidator(MyBean.class, "myValidMethod"); + assertViolation(() -> validator1.accept(bean, new Object[] {null, 2}), "myValidMethod.arg0"); + assertViolation(() -> validator1.accept(bean, new Object[] {"test", 12}), "myValidMethod.arg1"); + + BiConsumer validator2 = createValidator(MyBean.class, "myValidatedParameterMethod"); + assertViolation(() -> validator2.accept(bean, new Object[] {new ConstrainedInput(100)}), "integerValue"); } @Test void shouldRaiseValidationErrorForAnnotatedParamsWithGroups() { - Consumer validator1 = createValidator(MyValidationGroupsBean.class, "myValidMethodWithGroup"); - assertViolation(() -> validator1.accept(new Object[] {null}), "myValidMethodWithGroup.arg0"); + MyValidationGroupsBean bean = new MyValidationGroupsBean(); - Consumer validator2 = createValidator(MyValidationGroupsBean.class, "myValidMethodWithGroupOnType"); - assertViolation(() -> validator2.accept(new Object[] {null}), "myValidMethodWithGroupOnType.arg0"); + BiConsumer validator1 = createValidator(MyValidationGroupsBean.class, "myValidMethodWithGroup"); + assertViolation(() -> validator1.accept(bean, new Object[] {null}), "myValidMethodWithGroup.arg0"); + + BiConsumer validator2 = createValidator(MyValidationGroupsBean.class, "myValidMethodWithGroupOnType"); + assertViolation(() -> validator2.accept(bean, new Object[] {null}), "myValidMethodWithGroupOnType.arg0"); } @Test void shouldRecognizeMethodsThatRequireValidation() { - Consumer validator1 = createValidator(RequiresValidationBean.class, "processConstrainedValue"); + BiConsumer validator1 = createValidator(RequiresValidationBean.class, "processConstrainedValue"); assertThat(validator1).isNotNull(); - Consumer validator2 = createValidator(RequiresValidationBean.class, "processValidInput"); + BiConsumer validator2 = createValidator(RequiresValidationBean.class, "processValidInput"); assertThat(validator2).isNotNull(); - Consumer validator3 = createValidator(RequiresValidationBean.class, "processValidatedInput"); + BiConsumer validator3 = createValidator(RequiresValidationBean.class, "processValidatedInput"); assertThat(validator3).isNotNull(); - Consumer validator4 = createValidator(RequiresValidationBean.class, "processValue"); + BiConsumer validator4 = createValidator(RequiresValidationBean.class, "processValue"); assertThat(validator4).isNull(); } - private Consumer createValidator(Class handlerType, String methodName) { + private BiConsumer createValidator(Class handlerType, String methodName) { return ValidationHelper.create(Validation.buildDefaultValidatorFactory().getValidator()) .getValidationHelperFor(findHandlerMethod(handlerType, methodName)); }