From 4dcb9ea7c65d1e99bdb20773b316ce5b81efecf4 Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Mon, 1 Nov 2021 10:35:44 +0000 Subject: [PATCH] Support Locale as a controller method argument Closes gh-3 --- .../src/docs/asciidoc/index.adoc | 28 +---- ...hingEnvironmentMethodArgumentResolver.java | 25 +++- .../ArgumentMethodArgumentResolverTests.java | 3 +- ...chingEnvironmentArgumentResolverTests.java | 109 ++++++++++++++++++ 4 files changed, 135 insertions(+), 30 deletions(-) create mode 100644 spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/DataFetchingEnvironmentArgumentResolverTests.java diff --git a/spring-graphql-docs/src/docs/asciidoc/index.adoc b/spring-graphql-docs/src/docs/asciidoc/index.adoc index 088e9dc1..b14fab74 100644 --- a/spring-graphql-docs/src/docs/asciidoc/index.adoc +++ b/spring-graphql-docs/src/docs/asciidoc/index.adoc @@ -593,15 +593,15 @@ See <>. | `GraphQLContext` | For access to the context from the `DataFetchingEnvironment`. -See <>. | `DataFetchingFieldSelectionSet` | For access to the selection set for the query through the `DataFetchingEnvironment`. -See <>. + +| `Locale`, `Optional` +| For access to the `Locale` from the `DataFetchingEnvironment`. | `DataFetchingEnvironment` | For direct access to the underlying `DataFetchingEnvironment`. -See <>. |=== @@ -721,28 +721,6 @@ instead. ==== -[[controllers-schema-mapping-graphql-context]] -==== `GraphQLContext` - -To access the `GraphQLContext` from the `DataFetchingEnvironment`, declare a method -parameter of the same type. - - -[[controllers-schema-mapping-selection-set]] -==== `DataFetchingFieldSelectionSet` - -To access the `DataFetchingFieldSelectionSet` from the `DataFetchingEnvironment`, declare -a method parameter of the same type. This is useful to peek ahead at the fields that need -to be fetched. - - -[[controllers-schema-mapping-environment]] -==== `DataFetchingEnvironment` - -To access the `DataFetchingEnvironment` directly, declare a method parameter of the same -type. - - [[controllers-batch-mapping]] === `@BatchMapping` diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/DataFetchingEnvironmentMethodArgumentResolver.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/DataFetchingEnvironmentMethodArgumentResolver.java index 5df9cb2a..9d7313f3 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/DataFetchingEnvironmentMethodArgumentResolver.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/DataFetchingEnvironmentMethodArgumentResolver.java @@ -15,6 +15,9 @@ */ package org.springframework.graphql.data.method.annotation.support; +import java.util.Locale; +import java.util.Optional; + import graphql.GraphQLContext; import graphql.schema.DataFetchingEnvironment; import graphql.schema.DataFetchingFieldSelectionSet; @@ -23,8 +26,13 @@ import org.springframework.core.MethodParameter; import org.springframework.graphql.data.method.HandlerMethodArgumentResolver; /** - * Resolver for {@link DataFetchingEnvironment} as well as arguments of type - * {@link GraphQLContext} or {@link DataFetchingFieldSelectionSet}. + * Resolver for {@link DataFetchingEnvironment} and related values that can be + * accessed through the {@link DataFetchingEnvironment} such as: + *
    + *
  • {@link GraphQLContext} + *
  • {@link DataFetchingFieldSelectionSet} + *
  • {@link Locale} or {@code Optional} + *
as well as arguments of type * * @author Rossen Stoyanchev * @since 1.0.0 @@ -35,7 +43,12 @@ public class DataFetchingEnvironmentMethodArgumentResolver implements HandlerMet public boolean supportsParameter(MethodParameter parameter) { Class type = parameter.getParameterType(); return (type.equals(DataFetchingEnvironment.class) || type.equals(GraphQLContext.class) || - type.equals(DataFetchingFieldSelectionSet.class)); + type.equals(DataFetchingFieldSelectionSet.class) || + type.equals(Locale.class) || isOptionalLocale(parameter)); + } + + private static boolean isOptionalLocale(MethodParameter parameter) { + return parameter.nestedIfOptional().getNestedParameterType().equals(Locale.class); } @Override @@ -47,6 +60,12 @@ public class DataFetchingEnvironmentMethodArgumentResolver implements HandlerMet else if (type.equals(DataFetchingFieldSelectionSet.class)) { return environment.getSelectionSet(); } + else if (type.equals(Locale.class)) { + return environment.getLocale(); + } + else if (isOptionalLocale(parameter)) { + return Optional.ofNullable(environment.getLocale()); + } else if (type.equals(DataFetchingEnvironment.class)) { return environment; } diff --git a/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/ArgumentMethodArgumentResolverTests.java b/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/ArgumentMethodArgumentResolverTests.java index bda1202b..94d6a1d7 100644 --- a/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/ArgumentMethodArgumentResolverTests.java +++ b/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/ArgumentMethodArgumentResolverTests.java @@ -118,8 +118,7 @@ class ArgumentMethodArgumentResolverTests { } private DataFetchingEnvironment initEnvironment(String jsonPayload) throws JsonProcessingException { - Map arguments = mapper.readValue(jsonPayload, new TypeReference>() { - }); + Map arguments = mapper.readValue(jsonPayload, new TypeReference>() {}); return DataFetchingEnvironmentImpl.newDataFetchingEnvironment().arguments(arguments).build(); } diff --git a/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/DataFetchingEnvironmentArgumentResolverTests.java b/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/DataFetchingEnvironmentArgumentResolverTests.java new file mode 100644 index 00000000..bd57ace8 --- /dev/null +++ b/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/DataFetchingEnvironmentArgumentResolverTests.java @@ -0,0 +1,109 @@ +/* + * Copyright 2002-2021 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.support; + +import java.lang.reflect.Method; +import java.util.Locale; +import java.util.Optional; + +import graphql.GraphQLContext; +import graphql.schema.DataFetchingEnvironment; +import graphql.schema.DataFetchingEnvironmentImpl; +import graphql.schema.DataFetchingFieldSelectionSet; +import org.junit.jupiter.api.Test; + +import org.springframework.core.MethodParameter; +import org.springframework.util.ClassUtils; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +/** + * Unit tests for {@link DataFetchingEnvironmentMethodArgumentResolver}. + * @author Rossen Stoyanchev + */ +public class DataFetchingEnvironmentArgumentResolverTests { + + private static final Method handleMethod = ClassUtils.getMethod( + DataFetchingEnvironmentArgumentResolverTests.class, "handle", (Class[]) null); + + + private final DataFetchingEnvironmentMethodArgumentResolver resolver = + new DataFetchingEnvironmentMethodArgumentResolver(); + + @Test + void supportsParameter() { + assertThat(this.resolver.supportsParameter(parameter(0))).isTrue(); + assertThat(this.resolver.supportsParameter(parameter(1))).isTrue(); + assertThat(this.resolver.supportsParameter(parameter(2))).isTrue(); + assertThat(this.resolver.supportsParameter(parameter(3))).isTrue(); + + assertThat(this.resolver.supportsParameter(parameter(4))).isFalse(); + } + + @Test + void resolveGraphQlContext() { + GraphQLContext context = GraphQLContext.newContext().build(); + DataFetchingEnvironment environment = + DataFetchingEnvironmentImpl.newDataFetchingEnvironment().graphQLContext(context).build(); + Object actual = this.resolver.resolveArgument(parameter(0), environment); + + assertThat(actual).isSameAs(context); + } + + @Test + void resolveSelectionSet() { + DataFetchingFieldSelectionSet selectionSet = mock(DataFetchingFieldSelectionSet.class); + DataFetchingEnvironment environment = + DataFetchingEnvironmentImpl.newDataFetchingEnvironment().selectionSet(selectionSet).build(); + Object actual = this.resolver.resolveArgument(parameter(1), environment); + + assertThat(actual).isSameAs(selectionSet); + } + + @Test + void resolveLocale() { + Locale locale = Locale.ITALIAN; + DataFetchingEnvironment environment = + DataFetchingEnvironmentImpl.newDataFetchingEnvironment().locale(locale).build(); + Object actual = this.resolver.resolveArgument(parameter(2), environment); + + assertThat(actual).isSameAs(locale); + } + + @Test + void resolveOptionalLocale() { + Locale locale = Locale.ITALIAN; + DataFetchingEnvironment environment = + DataFetchingEnvironmentImpl.newDataFetchingEnvironment().locale(locale).build(); + Optional actual = (Optional) this.resolver.resolveArgument(parameter(3), environment); + + assertThat(actual).isNotNull(); + assertThat(actual.isPresent()).isTrue(); + assertThat(actual.get()).isSameAs(locale); + } + + private MethodParameter parameter(int index) { + return new MethodParameter(handleMethod, index); + } + + + @SuppressWarnings("OptionalUsedAsFieldOrParameterType") + public void handle(GraphQLContext graphQLContext, DataFetchingFieldSelectionSet selectionSet, + Locale locale, Optional optionalLocale, String s) { + } + +}