From 5deba1930fdc058633b2cdfd32817517ece936cd Mon Sep 17 00:00:00 2001 From: dugenkui03 Date: Sat, 19 Feb 2022 20:34:15 +0800 Subject: [PATCH] Replace argument type with `@Source` to determine source/parent Closes gh-296 --- .../src/docs/asciidoc/index.adoc | 12 +++--- .../data/method/annotation/Source.java | 38 +++++++++++++++++++ .../support/SourceMethodArgumentResolver.java | 16 +++----- .../support/SchemaMappingDetectionTests.java | 9 +++-- .../support/SchemaMappingInvocationTests.java | 3 +- 5 files changed, 56 insertions(+), 22 deletions(-) create mode 100644 spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/Source.java diff --git a/spring-graphql-docs/src/docs/asciidoc/index.adoc b/spring-graphql-docs/src/docs/asciidoc/index.adoc index b059ef7ac..10820e6cf 100644 --- a/spring-graphql-docs/src/docs/asciidoc/index.adoc +++ b/spring-graphql-docs/src/docs/asciidoc/index.adoc @@ -1009,7 +1009,7 @@ parent type name, and the field name: public class BookController { @SchemaMapping(typeName="Book", field="author") - public Author getAuthor(Book book) { + public Author getAuthor(@Source Book book) { // ... } } @@ -1026,7 +1026,7 @@ defaults to type "Book" and field "author": public class BookController { @SchemaMapping - public Author author(Book book) { + public Author author(@Source Book book) { // ... } } @@ -1098,7 +1098,7 @@ See <>. | For access to field arguments through a project interface. See <>. -| Source +| @Source | For access to the source (i.e. parent/container) instance of the field. See <>. @@ -1287,11 +1287,11 @@ For example: [[controllers-schema-mapping-source]] -==== Source +==== @Source In GraphQL Java, the `DataFetchingEnvironment` provides access to the source (i.e. parent/container) instance of the field. To access this, simply declare a method parameter -of the expected target type. +annotated with `@Source`. [source,java,indent=0,subs="verbatim,quotes"] ---- @@ -1299,7 +1299,7 @@ of the expected target type. public class BookController { @SchemaMapping - public Author author(Book book) { + public Author author(@Source Book book) { // ... } } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/Source.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/Source.java new file mode 100644 index 000000000..d77c71785 --- /dev/null +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/Source.java @@ -0,0 +1,38 @@ +/* + * Copyright 2002-2022 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.graphql.data.method.annotation; + +import graphql.schema.DataFetchingEnvironment; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation to bind a method parameter to the + * {@link DataFetchingEnvironment#getSource() source/parent} instance of the field. + * + * @author Genkui Du + * @since 1.0.0 + */ +@Target(ElementType.PARAMETER) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface Source { + +} diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/SourceMethodArgumentResolver.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/SourceMethodArgumentResolver.java index b3cea6d67..ffa02bbc1 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/SourceMethodArgumentResolver.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/SourceMethodArgumentResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2022 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. @@ -15,32 +15,26 @@ */ package org.springframework.graphql.data.method.annotation.support; -import java.util.Collection; - import graphql.schema.DataFetchingEnvironment; -import org.springframework.beans.BeanUtils; import org.springframework.core.MethodParameter; import org.springframework.graphql.data.method.HandlerMethodArgumentResolver; +import org.springframework.graphql.data.method.annotation.Source; import org.springframework.util.Assert; /** * Resolver for the source/parent of a field, obtained via * {@link DataFetchingEnvironment#getSource()}. * - *

This resolver supports any non-simple value type, also excluding arrays - * and collections, and therefore must be ordered last, in a fallback mode, - * allowing other resolvers to resolve the argument first. - * * @author Rossen Stoyanchev + * @author Genkui Du * @since 1.0.0 */ public class SourceMethodArgumentResolver implements HandlerMethodArgumentResolver { @Override public boolean supportsParameter(MethodParameter parameter) { - Class type = parameter.getParameterType(); - return (!BeanUtils.isSimpleValueType(type) && !type.isArray() && !Collection.class.isAssignableFrom(type)); + return parameter.getParameterAnnotation(Source.class) != null; } @Override @@ -49,7 +43,7 @@ public Object resolveArgument(MethodParameter parameter, DataFetchingEnvironment Assert.isInstanceOf(parameter.getParameterType(), source, "The declared parameter of type '" + parameter.getParameterType() + "' " + "does not match the type of the source Object '" + source.getClass() + "'."); - return source; + return environment.getSource(); } } diff --git a/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/SchemaMappingDetectionTests.java b/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/SchemaMappingDetectionTests.java index 50f3df1ea..4aa29b165 100644 --- a/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/SchemaMappingDetectionTests.java +++ b/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/SchemaMappingDetectionTests.java @@ -21,6 +21,7 @@ import graphql.schema.DataFetchingEnvironment; import graphql.schema.idl.RuntimeWiring; import org.junit.jupiter.api.Test; +import org.springframework.graphql.data.method.annotation.Source; import reactor.core.publisher.Flux; import org.springframework.context.annotation.AnnotationConfigApplicationContext; @@ -118,7 +119,7 @@ public Book bookById(@Argument String id) { } @MutationMapping - public void saveBook(Book book) { + public void saveBook(@Source Book book) { } @SubscriptionMapping @@ -127,7 +128,7 @@ public Flux bookSearch(@Argument String author) { } @SchemaMapping - public Author author(DataFetchingEnvironment environment, Book book) { + public Author author(DataFetchingEnvironment environment, @Source Book book) { return null; } @@ -139,7 +140,7 @@ public Book bookByIdWithNonMatchingMethodName(@Argument String id) { } @MutationMapping("saveBookCustomized") - public void saveBookWithNonMatchingMethodName(Book book) { + public void saveBookWithNonMatchingMethodName(@Source Book book) { } @SubscriptionMapping("bookSearchCustomized") @@ -148,7 +149,7 @@ public Flux bookSearchWithNonMatchingMethodName(@Argument String author) { } @SchemaMapping("authorCustomized") - public Author authorWithNonMatchingMethodName(Book book) { + public Author authorWithNonMatchingMethodName(@Source Book book) { return null; } } diff --git a/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/SchemaMappingInvocationTests.java b/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/SchemaMappingInvocationTests.java index 346e915d2..5e9756896 100644 --- a/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/SchemaMappingInvocationTests.java +++ b/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/SchemaMappingInvocationTests.java @@ -23,6 +23,7 @@ import graphql.schema.DataFetchingEnvironment; import org.dataloader.DataLoader; import org.junit.jupiter.api.Test; +import org.springframework.graphql.data.method.annotation.Source; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.test.StepVerifier; @@ -251,7 +252,7 @@ public List booksByProjectedCriteria(@Argument BookProjection criteria) { } @SchemaMapping - public CompletableFuture author(Book book, DataLoader dataLoader) { + public CompletableFuture author(@Source Book book, DataLoader dataLoader) { return dataLoader.load(book.getAuthorId()); }