Skip to content

Commit 581b110

Browse files
committed
Ensure resolved bean instance is used for validation
Closes gh-624
1 parent 3b100c6 commit 581b110

File tree

4 files changed

+41
-34
lines changed

4 files changed

+41
-34
lines changed

spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/AnnotatedControllerConfigurer.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import java.util.Set;
2828
import java.util.concurrent.Callable;
2929
import java.util.concurrent.Executor;
30+
import java.util.function.BiConsumer;
3031
import java.util.function.Consumer;
3132
import java.util.stream.Collectors;
3233

@@ -492,7 +493,7 @@ static class SchemaMappingDataFetcher implements DataFetcher<Object> {
492493
private final HandlerMethodArgumentResolverComposite argumentResolvers;
493494

494495
@Nullable
495-
private final Consumer<Object[]> methodValidationHelper;
496+
private final BiConsumer<Object, Object[]> methodValidationHelper;
496497

497498
@Nullable
498499
private final Executor executor;

spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/DataFetcherHandlerMethod.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
import java.util.Arrays;
1919
import java.util.concurrent.Executor;
20-
import java.util.function.Consumer;
20+
import java.util.function.BiConsumer;
2121

2222
import graphql.schema.DataFetchingEnvironment;
2323
import org.reactivestreams.Publisher;
@@ -50,7 +50,7 @@ public class DataFetcherHandlerMethod extends InvocableHandlerMethodSupport {
5050

5151
private final HandlerMethodArgumentResolverComposite resolvers;
5252

53-
private final Consumer<Object[]> validationHelper;
53+
private final BiConsumer<Object, Object[]> validationHelper;
5454

5555
private final ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
5656

@@ -66,12 +66,13 @@ public class DataFetcherHandlerMethod extends InvocableHandlerMethodSupport {
6666
*/
6767
public DataFetcherHandlerMethod(
6868
HandlerMethod handlerMethod, HandlerMethodArgumentResolverComposite resolvers,
69-
@Nullable Consumer<Object[]> validationHelper, @Nullable Executor executor, boolean subscription) {
69+
@Nullable BiConsumer<Object, Object[]> validationHelper, @Nullable Executor executor,
70+
boolean subscription) {
7071

7172
super(handlerMethod, executor);
7273
Assert.isTrue(!resolvers.getResolvers().isEmpty(), "No argument resolvers");
7374
this.resolvers = resolvers;
74-
this.validationHelper = (validationHelper != null ? validationHelper : args -> {});
75+
this.validationHelper = (validationHelper != null ? validationHelper : (controller, args) -> {});
7576
this.subscription = subscription;
7677
}
7778

@@ -179,7 +180,7 @@ private Object[] getMethodArgumentValues(
179180

180181
@Nullable
181182
private Object validateAndInvoke(Object[] args, DataFetchingEnvironment environment) {
182-
this.validationHelper.accept(args);
183+
this.validationHelper.accept(getBean(), args);
183184
return doInvoke(environment.getGraphQlContext(), args);
184185
}
185186

spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/ValidationHelper.java

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@
1616
package org.springframework.graphql.data.method.annotation.support;
1717

1818
import java.lang.annotation.Annotation;
19+
import java.lang.reflect.Method;
1920
import java.util.Set;
20-
import java.util.function.Consumer;
21+
import java.util.function.BiConsumer;
2122

2223
import jakarta.validation.Constraint;
2324
import jakarta.validation.ConstraintViolation;
@@ -61,7 +62,7 @@ private ValidationHelper(Validator validator) {
6162
* {@link Validated}, {@link Valid}, or {@link Constraint} annotations.
6263
*/
6364
@Nullable
64-
public Consumer<Object[]> getValidationHelperFor(HandlerMethod handlerMethod) {
65+
public BiConsumer<Object, Object[]> getValidationHelperFor(HandlerMethod handlerMethod) {
6566

6667
boolean requiresMethodValidation = false;
6768
Class<?>[] methodValidationGroups = null;
@@ -75,7 +76,7 @@ else if (findAnnotation(handlerMethod, Valid.class) != null) {
7576
requiresMethodValidation = true;
7677
}
7778

78-
Consumer<Object[]> parameterValidator = null;
79+
BiConsumer<Object, Object[]> parameterValidator = null;
7980
MethodParameter[] parameters = handlerMethod.getMethodParameters();
8081

8182
for (int i = 0; i < parameters.length; i++) {
@@ -94,7 +95,7 @@ else if (annot.annotationType().equals(Validated.class)) {
9495
}
9596
}
9697

97-
Consumer<Object[]> result = (requiresMethodValidation ?
98+
BiConsumer<Object, Object[]> result = (requiresMethodValidation ?
9899
new HandlerMethodValidator(handlerMethod, methodValidationGroups) : null);
99100

100101
if (parameterValidator != null) {
@@ -141,24 +142,24 @@ public static ValidationHelper create(Validator validator) {
141142
/**
142143
* Callback to apply validation to the invocation of a {@link HandlerMethod}.
143144
*/
144-
private class HandlerMethodValidator implements Consumer<Object[]> {
145+
private class HandlerMethodValidator implements BiConsumer<Object, Object[]> {
145146

146-
private final HandlerMethod handlerMethod;
147+
private final Method method;
147148

148149
private final Class<?>[] validationGroups;
149150

150151
HandlerMethodValidator(HandlerMethod handlerMethod, @Nullable Class<?>[] validationGroups) {
151152
Assert.notNull(handlerMethod, "HandlerMethod is required");
152-
this.handlerMethod = handlerMethod;
153+
this.method = handlerMethod.getMethod();
153154
this.validationGroups = (validationGroups != null ? validationGroups : new Class<?>[] {});
154155
}
155156

156157
@Override
157-
public void accept(Object[] arguments) {
158+
public void accept(Object controller, Object[] arguments) {
158159

159160
Set<ConstraintViolation<Object>> violations =
160-
ValidationHelper.this.validator.forExecutables().validateParameters(
161-
this.handlerMethod.getBean(), this.handlerMethod.getMethod(), arguments, this.validationGroups);
161+
ValidationHelper.this.validator.forExecutables()
162+
.validateParameters(controller, this.method, arguments, this.validationGroups);
162163

163164
if (!violations.isEmpty()) {
164165
throw new ConstraintViolationException(violations);
@@ -172,7 +173,7 @@ public void accept(Object[] arguments) {
172173
* because it's annotated with Spring's {@code @Validated} rather than with
173174
* {@code @Valid}.
174175
*/
175-
private class MethodParameterValidator implements Consumer<Object[]> {
176+
private class MethodParameterValidator implements BiConsumer<Object, Object[]> {
176177

177178
private final int index;
178179

@@ -184,7 +185,7 @@ private class MethodParameterValidator implements Consumer<Object[]> {
184185
}
185186

186187
@Override
187-
public void accept(Object[] arguments) {
188+
public void accept(Object controller, Object[] arguments) {
188189

189190
Set<ConstraintViolation<Object>> violations =
190191
ValidationHelper.this.validator.validate(arguments[this.index], this.validationGroups);

spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/ValidationHelperTests.java

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
import java.lang.annotation.RetentionPolicy;
2121
import java.lang.reflect.Method;
2222
import java.util.Arrays;
23-
import java.util.function.Consumer;
23+
import java.util.function.BiConsumer;
2424

2525
import jakarta.validation.ConstraintViolation;
2626
import jakarta.validation.ConstraintViolationException;
@@ -54,45 +54,49 @@ void shouldFailWithNullValidator() {
5454

5555
@Test
5656
void shouldIgnoreMethodsWithoutAnnotations() {
57-
Consumer<Object[]> validator = createValidator(MyBean.class, "notValidatedMethod");
57+
BiConsumer<Object, Object[]> validator = createValidator(MyBean.class, "notValidatedMethod");
5858
assertThat(validator).isNull();
5959
}
6060

6161
@Test
6262
void shouldRaiseValidationErrorForAnnotatedParams() {
63-
Consumer<Object[]> validator1 = createValidator(MyBean.class, "myValidMethod");
64-
assertViolation(() -> validator1.accept(new Object[] {null, 2}), "myValidMethod.arg0");
65-
assertViolation(() -> validator1.accept(new Object[] {"test", 12}), "myValidMethod.arg1");
63+
MyBean bean = new MyBean();
6664

67-
Consumer<Object[]> validator2 = createValidator(MyBean.class, "myValidatedParameterMethod");
68-
assertViolation(() -> validator2.accept(new Object[] {new ConstrainedInput(100)}), "integerValue");
65+
BiConsumer<Object, Object[]> validator1 = createValidator(MyBean.class, "myValidMethod");
66+
assertViolation(() -> validator1.accept(bean, new Object[] {null, 2}), "myValidMethod.arg0");
67+
assertViolation(() -> validator1.accept(bean, new Object[] {"test", 12}), "myValidMethod.arg1");
68+
69+
BiConsumer<Object, Object[]> validator2 = createValidator(MyBean.class, "myValidatedParameterMethod");
70+
assertViolation(() -> validator2.accept(bean, new Object[] {new ConstrainedInput(100)}), "integerValue");
6971
}
7072

7173
@Test
7274
void shouldRaiseValidationErrorForAnnotatedParamsWithGroups() {
73-
Consumer<Object[]> validator1 = createValidator(MyValidationGroupsBean.class, "myValidMethodWithGroup");
74-
assertViolation(() -> validator1.accept(new Object[] {null}), "myValidMethodWithGroup.arg0");
75+
MyValidationGroupsBean bean = new MyValidationGroupsBean();
76+
77+
BiConsumer<Object, Object[]> validator1 = createValidator(MyValidationGroupsBean.class, "myValidMethodWithGroup");
78+
assertViolation(() -> validator1.accept(bean, new Object[] {null}), "myValidMethodWithGroup.arg0");
7579

76-
Consumer<Object[]> validator2 = createValidator(MyValidationGroupsBean.class, "myValidMethodWithGroupOnType");
77-
assertViolation(() -> validator2.accept(new Object[] {null}), "myValidMethodWithGroupOnType.arg0");
80+
BiConsumer<Object, Object[]> validator2 = createValidator(MyValidationGroupsBean.class, "myValidMethodWithGroupOnType");
81+
assertViolation(() -> validator2.accept(bean, new Object[] {null}), "myValidMethodWithGroupOnType.arg0");
7882
}
7983

8084
@Test
8185
void shouldRecognizeMethodsThatRequireValidation() {
82-
Consumer<Object[]> validator1 = createValidator(RequiresValidationBean.class, "processConstrainedValue");
86+
BiConsumer<Object, Object[]> validator1 = createValidator(RequiresValidationBean.class, "processConstrainedValue");
8387
assertThat(validator1).isNotNull();
8488

85-
Consumer<Object[]> validator2 = createValidator(RequiresValidationBean.class, "processValidInput");
89+
BiConsumer<Object, Object[]> validator2 = createValidator(RequiresValidationBean.class, "processValidInput");
8690
assertThat(validator2).isNotNull();
8791

88-
Consumer<Object[]> validator3 = createValidator(RequiresValidationBean.class, "processValidatedInput");
92+
BiConsumer<Object, Object[]> validator3 = createValidator(RequiresValidationBean.class, "processValidatedInput");
8993
assertThat(validator3).isNotNull();
9094

91-
Consumer<Object[]> validator4 = createValidator(RequiresValidationBean.class, "processValue");
95+
BiConsumer<Object, Object[]> validator4 = createValidator(RequiresValidationBean.class, "processValue");
9296
assertThat(validator4).isNull();
9397
}
9498

95-
private Consumer<Object[]> createValidator(Class<?> handlerType, String methodName) {
99+
private BiConsumer<Object, Object[]> createValidator(Class<?> handlerType, String methodName) {
96100
return ValidationHelper.create(Validation.buildDefaultValidatorFactory().getValidator())
97101
.getValidationHelperFor(findHandlerMethod(handlerType, methodName));
98102
}

0 commit comments

Comments
 (0)