Skip to content

Commit e390d21

Browse files
authored
Merge pull request #888 from graphql-java-kickstart/feature/context-and-environment
Allow resolver methods to take both the context and the environment
2 parents 94a98a0 + 54b177e commit e390d21

4 files changed

Lines changed: 24 additions & 13 deletions

File tree

‎src/main/kotlin/graphql/kickstart/tools/resolver/FieldResolverScanner.kt‎

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ internal class FieldResolverScanner(val options: SchemaParserOptions) {
2525

2626
private val log = LoggerFactory.getLogger(javaClass)
2727

28-
private val allowedLastArgumentTypes = listOfNotNull(DataFetchingEnvironment::class.java, GraphQLContext::class.java, options.contextClass)
28+
private val allowedTrailingParameterTypes = listOfNotNull(DataFetchingEnvironment::class.java, GraphQLContext::class.java, options.contextClass)
2929

3030
private val methodsByNameCache = mutableMapOf<Pair<Class<out Any>, Boolean>, Map<String, List<Method>>>()
3131

@@ -171,10 +171,9 @@ internal class FieldResolverScanner(val options: SchemaParserOptions) {
171171
}
172172

173173
val methodParameterCount = method.parameterCountWithoutContinuation()
174-
val methodLastParameter = method.parameterTypes.getOrNull(methodParameterCount - 1)
175174

176-
val correctParameterCount = methodParameterCount == requiredCount ||
177-
(methodParameterCount == (requiredCount + 1) && allowedLastArgumentTypes.contains(methodLastParameter))
175+
val correctParameterCount = methodParameterCount >= requiredCount &&
176+
method.parameterTypes.slice(requiredCount until methodParameterCount).all { it in allowedTrailingParameterTypes }
178177
return correctParameterCount && appropriateFirstParameter
179178
}
180179

@@ -203,7 +202,7 @@ internal class FieldResolverScanner(val options: SchemaParserOptions) {
203202
val sourceLocation = field.sourceLocation?.let { "$sourceName:${it.line}" } ?: "<unknown>"
204203

205204
return "No method${if (scannedProperties) " or field" else ""} found as defined in schema $sourceLocation with any of the following signatures " +
206-
"(with or without one of $allowedLastArgumentTypes as the last argument), in priority order:\n${signatures.joinToString("\n ")}" +
205+
"(optionally followed by any of $allowedTrailingParameterTypes), in priority order:\n${signatures.joinToString("\n ")}" +
207206
if (isSubscription) "\n\nNote that a Subscription data fetcher must return a Publisher of events" else ""
208207
}
209208

‎src/main/kotlin/graphql/kickstart/tools/resolver/MethodFieldResolver.kt‎

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ internal class MethodFieldResolver(
4747

4848
private val isSuspendFunction = method.isSuspendFunction()
4949
private val numberOfParameters = method.parameterCountWithoutContinuation()
50-
private val hasAdditionalParameter = numberOfParameters == (field.inputValueDefinitions.size + getIndexOffset() + 1)
5150

5251
internal val objectMapper: ObjectMapper by lazy { options.objectMapperProvider.provide(field) }
5352

@@ -103,11 +102,10 @@ internal class MethodFieldResolver(
103102
}
104103
}
105104

106-
// Add DataFetchingEnvironment/Context argument
107-
if (this.hasAdditionalParameter) {
108-
// suspend functions have a trailing Continuation parameter
109-
when (this.method.parameterTypes[numberOfParameters - 1]) {
110-
null -> throw ResolverError("Expected at least one argument but got none, this is most likely a bug with graphql-java-tools")
105+
// Add DataFetchingEnvironment/Context arguments, stopping before the Continuation parameter of a suspend function
106+
val firstTrailingParameter = field.inputValueDefinitions.size + getIndexOffset()
107+
method.parameterTypes.slice(firstTrailingParameter until numberOfParameters).forEach { parameterType ->
108+
when (parameterType) {
111109
options.contextClass -> args.add { environment ->
112110
val context: Any? = environment.graphQlContext[options.contextClass]
113111
if (context != null) {

‎src/test/kotlin/graphql/kickstart/tools/MethodFieldResolverDataFetcherTest.kt‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,20 @@ class MethodFieldResolverDataFetcherTest {
278278
assertEquals(resolver.get(createEnvironment(DataClass(), context = context)), true)
279279
}
280280

281+
@Test
282+
fun `data fetcher passes custom context and environment if method has both as extra arguments`() {
283+
val customContext = ContextClass()
284+
val context = GraphQLContext.of(mapOf(ContextClass::class.java to customContext))
285+
val options = SchemaParserOptions.newOptions().contextClass(ContextClass::class).build()
286+
val resolver = createFetcher("active", options = options, resolver = object : GraphQLResolver<DataClass> {
287+
fun isActive(dataClass: DataClass, ctx: ContextClass, env: DataFetchingEnvironment): Boolean {
288+
return ctx == customContext && env.graphQlContext == context
289+
}
290+
})
291+
292+
assertEquals(resolver.get(createEnvironment(DataClass(), context = context)), true)
293+
}
294+
281295
@Test
282296
fun `data fetcher passes context to suspend function if method has extra argument and context is specified`() {
283297
val context = GraphQLContext.newContext().build()

‎src/test/kotlin/graphql/kickstart/tools/SchemaParserTest.kt‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1103,7 +1103,7 @@ class SchemaParserTest {
11031103
}
11041104

11051105
val expected = """
1106-
No method or field found as defined in schema <unknown>:3 with any of the following signatures (with or without one of [interface graphql.schema.DataFetchingEnvironment, class graphql.GraphQLContext] as the last argument), in priority order:
1106+
No method or field found as defined in schema <unknown>:3 with any of the following signatures (optionally followed by any of [interface graphql.schema.DataFetchingEnvironment, class graphql.GraphQLContext]), in priority order:
11071107
11081108
graphql.kickstart.tools.SchemaParserTest${"$"}parser should verify subscription resolver return type${"$"}Subscription.onItemCreated()
11091109
graphql.kickstart.tools.SchemaParserTest${"$"}parser should verify subscription resolver return type${"$"}Subscription.getOnItemCreated()
@@ -1143,7 +1143,7 @@ class SchemaParserTest {
11431143
}
11441144

11451145
val expected = """
1146-
No method or field found as defined in schema <unknown>:3 with any of the following signatures (with or without one of [interface graphql.schema.DataFetchingEnvironment, class graphql.GraphQLContext] as the last argument), in priority order:
1146+
No method or field found as defined in schema <unknown>:3 with any of the following signatures (optionally followed by any of [interface graphql.schema.DataFetchingEnvironment, class graphql.GraphQLContext]), in priority order:
11471147
11481148
graphql.kickstart.tools.SchemaParserTest${"$"}parser should verify subscription resolver generic future return type${"$"}Subscription.onItemCreated()
11491149
graphql.kickstart.tools.SchemaParserTest${"$"}parser should verify subscription resolver generic future return type${"$"}Subscription.getOnItemCreated()

0 commit comments

Comments
 (0)