Skip to content

Commit 0758574

Browse files
authored
Merge branch 'master' into 601-schema-max-tokens-limit
2 parents 34de62c + 40035bd commit 0758574

File tree

6 files changed

+122
-34
lines changed

6 files changed

+122
-34
lines changed

pom.xml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@
127127
<dependency>
128128
<groupId>ch.qos.logback</groupId>
129129
<artifactId>logback-classic</artifactId>
130-
<version>1.2.9</version>
130+
<version>1.2.10</version>
131131
<scope>test</scope>
132132
<exclusions>
133133
<exclusion>
@@ -180,7 +180,7 @@
180180
<plugin>
181181
<groupId>org.codehaus.mojo</groupId>
182182
<artifactId>build-helper-maven-plugin</artifactId>
183-
<version>3.2.0</version>
183+
<version>3.3.0</version>
184184
<executions>
185185
<execution>
186186
<id>add-test-source</id>
@@ -250,7 +250,7 @@
250250
<plugin>
251251
<groupId>org.apache.maven.plugins</groupId>
252252
<artifactId>maven-jar-plugin</artifactId>
253-
<version>3.2.0</version>
253+
<version>3.2.1</version>
254254
<executions>
255255
<execution>
256256
<id>test-jar</id>

src/main/kotlin/graphql/kickstart/tools/SchemaParser.kt

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import graphql.language.*
1010
import graphql.schema.*
1111
import graphql.schema.idl.RuntimeWiring
1212
import graphql.schema.idl.ScalarInfo
13-
import graphql.schema.idl.SchemaGeneratorHelperExt
1413
import graphql.schema.visibility.NoIntrospectionGraphqlFieldVisibility
1514
import org.slf4j.LoggerFactory
1615
import kotlin.reflect.KClass
@@ -58,7 +57,6 @@ class SchemaParser internal constructor(
5857

5958
private val codeRegistryBuilder = GraphQLCodeRegistry.newCodeRegistry()
6059

61-
private val schemaGeneratorHelper = SchemaGeneratorHelperExt()
6260
private val schemaGeneratorDirectiveHelper = SchemaGeneratorDirectiveHelper()
6361
private val schemaDirectiveParameters = SchemaGeneratorDirectiveHelper.Parameters(null, runtimeWiring, null, codeRegistryBuilder)
6462

@@ -307,18 +305,21 @@ class SchemaParser internal constructor(
307305
names.add(directive.name)
308306
val graphQLDirective = GraphQLDirective.newDirective()
309307
.name(directive.name)
308+
.description(getDocumentation(directive, options))
309+
.comparatorRegistry(runtimeWiring.comparatorRegistry)
310+
.validLocation(directiveLocation)
310311
.apply {
311312
directive.arguments.forEach { arg ->
312313
argument(GraphQLArgument.newArgument()
313314
.name(arg.name)
314315
.type(buildDirectiveInputType(arg.value))
316+
.valueLiteral(arg.value)
315317
.build())
316318
}
317319
}
318320
.build()
319321

320-
321-
output.add(schemaGeneratorHelper.buildAppliedDirective(directive, graphQLDirective, directiveLocation, runtimeWiring.comparatorRegistry))
322+
output.add(graphQLDirective)
322323
}
323324
}
324325

@@ -392,12 +393,12 @@ class SchemaParser internal constructor(
392393
}
393394

394395
private fun determineInputType(typeDefinition: Type<*>, inputObjects: List<GraphQLInputObjectType>, referencingInputObjects: Set<String>) =
395-
determineInputType(GraphQLInputType::class, typeDefinition, permittedTypesForInputObject, inputObjects, referencingInputObjects) as GraphQLInputType
396+
determineInputType(GraphQLInputType::class, typeDefinition, permittedTypesForInputObject, inputObjects, referencingInputObjects)
396397

397398
private fun <T : Any> determineInputType(expectedType: KClass<T>,
398399
typeDefinition: Type<*>, allowedTypeReferences: Set<String>,
399400
inputObjects: List<GraphQLInputObjectType>,
400-
referencingInputObjects: Set<String>): GraphQLType =
401+
referencingInputObjects: Set<String>): GraphQLInputType =
401402
when (typeDefinition) {
402403
is ListType -> GraphQLList(determineType(expectedType, typeDefinition.type, allowedTypeReferences, inputObjects))
403404
is NonNullType -> GraphQLNonNull(determineType(expectedType, typeDefinition.type, allowedTypeReferences, inputObjects))

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

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import graphql.schema.DataFetchingEnvironment
1212
import org.apache.commons.lang3.ClassUtils
1313
import org.apache.commons.lang3.reflect.FieldUtils
1414
import org.slf4j.LoggerFactory
15+
import java.lang.reflect.AccessibleObject
1516
import java.lang.reflect.Method
1617
import java.lang.reflect.Modifier
1718
import java.lang.reflect.Type
@@ -44,13 +45,13 @@ internal class FieldResolverScanner(val options: SchemaParserOptions) {
4445
private fun findFieldResolver(field: FieldDefinition, search: Search, scanProperties: Boolean): FieldResolver? {
4546
val method = findResolverMethod(field, search)
4647
if (method != null) {
47-
return MethodFieldResolver(field, search, options, method.apply { isAccessible = true })
48+
return MethodFieldResolver(field, search, options, method.apply(trySetAccessible(field, search.type)))
4849
}
4950

5051
if (scanProperties) {
5152
val property = findResolverProperty(field, search)
5253
if (property != null) {
53-
return PropertyFieldResolver(field, search, options, property.apply { isAccessible = true })
54+
return PropertyFieldResolver(field, search, options, property.apply(trySetAccessible(field, search.type)))
5455
}
5556
}
5657

@@ -61,6 +62,15 @@ internal class FieldResolverScanner(val options: SchemaParserOptions) {
6162
return null
6263
}
6364

65+
private fun trySetAccessible(field: FieldDefinition, type: JavaType): AccessibleObject.() -> Unit = {
66+
try {
67+
isAccessible = true
68+
} catch (e: RuntimeException) {
69+
log.warn("Unable to make field ${type.unwrap().name}#${field.name} accessible. " +
70+
"Be sure to provide a resolver or open the enclosing module if possible.")
71+
}
72+
}
73+
6474
private fun missingFieldResolver(field: FieldDefinition, searches: List<Search>, scanProperties: Boolean): FieldResolver {
6575
return if (options.allowUnimplementedResolvers || options.missingResolverDataFetcher != null) {
6676
if (options.allowUnimplementedResolvers) {

src/main/kotlin/graphql/kickstart/tools/util/Utils.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ internal val Class<*>.declaredNonProxyMethods: List<JavaMethod>
5050
}
5151
}
5252

53-
internal fun getDocumentation(node: AbstractDescribedNode<*>, options: SchemaParserOptions): String? =
53+
internal fun getDocumentation(node: AbstractNode<*>, options: SchemaParserOptions): String? =
5454
when {
55-
node.description != null -> node.description.content
55+
node is AbstractDescribedNode<*> && node.description != null -> node.description.content
5656
!options.useCommentsForDescriptions -> null
5757
node.comments.isNullOrEmpty() -> null
5858
else -> node.comments.asSequence()

src/main/kotlin/graphql/schema/idl/SchemaGeneratorHelperExt.kt

Lines changed: 0 additions & 21 deletions
This file was deleted.
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
package graphql.kickstart.tools
2+
3+
import graphql.ExceptionWhileDataFetching
4+
import graphql.GraphQL
5+
import graphql.execution.AsyncExecutionStrategy
6+
import graphql.schema.GraphQLSchema
7+
import org.junit.Ignore
8+
import org.junit.Test
9+
import java.util.*
10+
11+
/**
12+
* Reflective access to private fields in closed modules is not possible since Java 17.
13+
* When using objects from closed modules in the schema the field resolver scanner will try to access their fields but fail.
14+
* If no other resolver is provided that will result in an [IllegalAccessException]
15+
*/
16+
class InaccessibleFieldResolverTest {
17+
18+
@Test
19+
@Ignore // TODO enable test after upgrading to 17
20+
fun `private field from closed module is not accessible`() {
21+
val schema: GraphQLSchema = SchemaParser.newParser()
22+
.schemaString(
23+
"""
24+
type Query {
25+
locale: Locale
26+
}
27+
28+
type Locale {
29+
country: String!
30+
languageTag: String!
31+
}
32+
""")
33+
.resolvers(Query())
34+
.build()
35+
.makeExecutableSchema()
36+
val gql: GraphQL = GraphQL.newGraphQL(schema)
37+
.queryExecutionStrategy(AsyncExecutionStrategy())
38+
.build()
39+
40+
val result = gql.execute(
41+
"""
42+
query {
43+
locale {
44+
country
45+
languageTag
46+
}
47+
}
48+
"""
49+
)
50+
51+
assertEquals(result.errors.size, 1)
52+
val exceptionWhileDataFetching = result.errors[0] as ExceptionWhileDataFetching
53+
assert(exceptionWhileDataFetching.exception is IllegalAccessException)
54+
}
55+
56+
@Test
57+
fun `private field from closed module is accessible through resolver`() {
58+
val schema: GraphQLSchema = SchemaParser.newParser()
59+
.schemaString(
60+
"""
61+
type Query {
62+
locale: Locale
63+
}
64+
65+
type Locale {
66+
country: String!
67+
languageTag: String!
68+
}
69+
""")
70+
.resolvers(Query(), LocaleResolver())
71+
.build()
72+
.makeExecutableSchema()
73+
val gql: GraphQL = GraphQL.newGraphQL(schema)
74+
.queryExecutionStrategy(AsyncExecutionStrategy())
75+
.build()
76+
77+
val data = assertNoGraphQlErrors(gql) {
78+
"""
79+
query {
80+
locale {
81+
country
82+
languageTag
83+
}
84+
}
85+
"""
86+
}
87+
88+
assertEquals(data["locale"], mapOf("country" to "US", "languageTag" to "en-US"))
89+
}
90+
91+
class Query : GraphQLQueryResolver {
92+
fun locale(): Locale = Locale.US
93+
}
94+
95+
class LocaleResolver : GraphQLResolver<Locale> {
96+
fun languageTag(locale: Locale): String = locale.toLanguageTag()
97+
}
98+
}

0 commit comments

Comments
 (0)