diff --git a/spring-graphql-docs/src/docs/asciidoc/index.adoc b/spring-graphql-docs/src/docs/asciidoc/index.adoc index 519a61a1..930241b9 100644 --- a/spring-graphql-docs/src/docs/asciidoc/index.adoc +++ b/spring-graphql-docs/src/docs/asciidoc/index.adoc @@ -414,8 +414,8 @@ Spring for GraphQL defines the `SelfDescribingDataFetcher` interface to allow a `DataFetcher` to expose return type information. All Spring `DataFetcher` implementations implement this interface. That includes those for <>, and those for <> and <> Spring Data repositories. For annotated -controllers, the return type is derived from the declared return type on `@SchemaMapping` -methods. +controllers, the return type is derived from the declared return type on a +`@SchemaMapping` method. On startup, Spring for GraphQL inspects all schema fields, `DataFetcher` registrations, and the properties of Java objects returned from `DataFetcher` implementations in order @@ -432,18 +432,23 @@ GraphQL schema inspection: <1> List of schema fields and their source types that are not mapped <2> List of schema types that are skipped, as explained next -There are limits to what schema mappings inspection can do, in particular when there is insufficient Java -type information. This is the case if an annotated controller method returns -`java.lang.Object` such as for a `union` type, or if a `DataFetcher` does not implement -`SelfDescribingDataFetcher`. If a schema type is skipped, its name is listed as such in -the report, and a DEBUG message is logged to provide a reason for why it was skipped. +There are limits to what schema mappings inspection can do, in particular when there is +insufficient Java type information. This is the case if an annotated controller method is +declared to return `java.lang.Object`, or if the return type has an unspecified generic +parameter such as `List`, or if the `DataFetcher` does not implement +`SelfDescribingDataFetcher` and the return type is not even known. In such cases, the +Java object type structure remains unknown, and the schema type is listed as skipped in +the resulting report. For every skipped type, a DEBUG message is logged to indicate why +it was skipped. -For schema `interface` types, the inspection currently checks only fields declared -directly on the interface against properties of the Java return type declared by the -`DataFetcher`. Additional fields on concrete implementations are not inspected, as there -is insufficient information about what Java types may be returned at runtime. This could -be improved in a future release to extend inspection to schema `interface` implementing -types to look for a match among subtypes of the declared Java return type. +Schema union types are always skipped because there is no way for a controller method to +declare such a return type in Java, and the Java type structure is unknown. + +Schema interface types are supported only as far as fields declared directly, which are +compared against properties on the Java type declared by a `SelfDescribingDataFetcher`. +Additional fields on concrete implementations are not inspected. This could be improved +in a future release to also inspect scheam `interface` implementation types and to try +to find a match among subtypes of the declared Java return type. [[execution.graphqlsource.operation-caching]] diff --git a/spring-graphql/src/main/java/org/springframework/graphql/execution/SchemaMappingInspector.java b/spring-graphql/src/main/java/org/springframework/graphql/execution/SchemaMappingInspector.java index b7f6e2e0..744fac55 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/execution/SchemaMappingInspector.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/execution/SchemaMappingInspector.java @@ -48,24 +48,30 @@ import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; /** - * Provide {@link #inspect(GraphQLSchema, RuntimeWiring)} method that checks if - * schema fields are covered by either a {@link DataFetcher} registration, or a - * Java object property. Fields that have neither are reported as unmapped in - * the output {@link Report}. + * Declares an {@link #inspect(GraphQLSchema, RuntimeWiring)} method that checks + * if schema fields are covered either by a {@link DataFetcher} registration, + * or match a Java object property. Fields that have neither are reported as + * "unmapped" in the resulting {@link Report Resport}. * - *

The inspection depends on {@code DataFetcher}s to expose return type - * information by implementing {@link SelfDescribingDataFetcher}. This allows - * checking if Java object types have properties that match schema fields. - * If a {@code DataFetcher} does not implement this interface, then the Java - * object type is not known, and the field type is reported as skipped. + *

The inspection depends on {@code DataFetcher}s to be + * {@link SelfDescribingDataFetcher} to be able to compare schema type and Java + * object type structure. If a {@code DataFetcher} does not implement this + * interface, then the Java type remains unknown, and the field type is reported + * as "skipped". * - *

The {@link SelfDescribingDataFetcher} for annotated controller methods - * exposes the declared return type of the controller method. If the return type - * is {@link Object} such as for a union, then the Java object structure is - * not known, and the field output type is reported as skipped. + *

The {@code SelfDescribingDataFetcher} for an annotated controller method + * derives type information from the controller method signature. If the declared + * return type is {@link Object}, or an unspecified generic parameter such as + * {@code List} then the Java type structure remains unknown, and the field + * output type is reported as skipped. * - *

Union types are automatically skipped because there is no way for an - * annotated controller method to declare the actual Java types. + *

Unions are always skipped because there is no way for an annotated + * controller method to express that in a return type, and the Java type + * structure remains unknown. + * + *

Interfaces are supported only as far as fields declared directly on the + * interface, which are compared against properties of the Java type declared + * by a {@code SelfDescribingDataFetcher}. * * @author Brian Clozel * @author Rossen Stoyanchev @@ -242,9 +248,9 @@ class SchemaMappingInspector { /** - * Container of unmapped fields and skipped types. - * @param unmappedFields fields with neither {@link DataFetcher} mapping nor Object property - * @param skippedTypes types that could not be verified, e.g. union + * The report produced as a result of schema mappings inspection. + * @param unmappedFields a map with type names as keys, and unmapped field names as values + * @param skippedTypes the names of types skipped by the inspection */ public record Report(MultiValueMap unmappedFields, Set skippedTypes) { diff --git a/spring-graphql/src/main/java/org/springframework/graphql/execution/SelfDescribingDataFetcher.java b/spring-graphql/src/main/java/org/springframework/graphql/execution/SelfDescribingDataFetcher.java index 12860f60..ea5eb325 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/execution/SelfDescribingDataFetcher.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/execution/SelfDescribingDataFetcher.java @@ -21,19 +21,20 @@ import graphql.schema.DataFetcher; import org.springframework.core.ResolvableType; /** - * Specialized {@link DataFetcher} that can provide information about itself. + * Specialized {@link DataFetcher} that exposes additional details such as + * return type information. + * * @author Brian Clozel + * @author Rossen Stoyanchev * @since 1.2.0 */ public interface SelfDescribingDataFetcher extends DataFetcher { /** - * The type that the {@link DataFetcher} returns. - *

This could be a type from a {@code @Controller} method declaration - * or the type expected to be returned by the {@link DataFetcher} - * possibly backed by a Spring Data repository. - * The concrete type of the returned instance might be a subclass. - * @return the type of the data returned by the data fetcher. + * The return type of this {@link DataFetcher}. + *

This could be derived from the method signature of an annotated + * {@code @Controller} method, the domain type of a {@link DataFetcher} + * backed by a Spring Data repository, or other. */ ResolvableType getReturnType();