Skip to content

Commit f2cd29c

Browse files
authored
Merge branch 'master' into feature/868-throw-jdk-proxy
2 parents fa3956f + 6c7101b commit f2cd29c

4 files changed

Lines changed: 163 additions & 220 deletions

File tree

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

Lines changed: 13 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import graphql.language.*
2323
import graphql.schema.*
2424
import graphql.schema.idl.RuntimeWiring
2525
import graphql.schema.idl.ScalarInfo
26-
import graphql.schema.visibility.BlockedFields
2726
import org.slf4j.LoggerFactory
2827
import kotlin.reflect.KClass
2928

@@ -79,14 +78,6 @@ class SchemaParser internal constructor(
7978
* Parses the given schema with respect to the given dictionary and returns GraphQL objects.
8079
*/
8180
fun parseSchemaObjects(): SchemaObjects {
82-
@Suppress("DEPRECATION")
83-
if (!options.introspectionEnabled) {
84-
// What the deprecated NoIntrospectionGraphqlFieldVisibility does. Its suggested replacement,
85-
// Introspection.enabledJvmWide, would also turn introspection off for every other schema in the JVM.
86-
// TODO remove this in 15.0.0 (#858)
87-
codeRegistryBuilder.fieldVisibility(BlockedFields.newBlock().addPattern("__.*").build())
88-
}
89-
// this overrides the above introspection enabled setting obviously... todo: add documentation
9081
options.fieldVisibility?.let { codeRegistryBuilder.fieldVisibility(it) }
9182

9283
// Create GraphQL objects
@@ -173,7 +164,7 @@ class SchemaParser internal constructor(
173164
val extensions = typeExtensions.extensionsOf<ObjectTypeExtensionDefinition>(name)
174165
val directives = sdlDirectives.directivesOf(objectDefinition, extensions)
175166
val fieldDefinitions = objectDefinition.withExtensions(typeExtensions).flatMap { it.fieldDefinitions }
176-
warnRepeatedFields(name, fieldDefinitions)
167+
rejectRepeated(name, "field", fieldDefinitions)
177168
val builder = GraphQLObjectType.newObject()
178169
.name(name)
179170
.definition(objectDefinition)
@@ -212,8 +203,8 @@ class SchemaParser internal constructor(
212203
inputObjectsInProgress: MutableSet<String>): GraphQLInputObjectType {
213204
val extensionDefinitions = typeExtensions.extensionsOf<InputObjectTypeExtensionDefinition>(definition.name)
214205
val directives = sdlDirectives.directivesOf(definition, extensionDefinitions)
215-
val fieldDefinitions = (extensionDefinitions + definition).flatMap { it.inputValueDefinitions }
216-
warnRepeatedFields(definition.name, fieldDefinitions)
206+
val inputValueDefinitions = definition.withExtensions(typeExtensions).flatMap { it.inputValueDefinitions }
207+
rejectRepeated(definition.name, "field", inputValueDefinitions)
217208

218209
inputObjectsInProgress.add(definition.name)
219210

@@ -224,7 +215,7 @@ class SchemaParser internal constructor(
224215
.description(getDocumentation(definition, options))
225216
.withSdlDirectives(directives, INPUT_OBJECT)
226217
.apply {
227-
fieldDefinitions.forEach { fieldDefinition ->
218+
inputValueDefinitions.forEach { fieldDefinition ->
228219
field(
229220
GraphQLInputObjectField.newInputObjectField()
230221
.name(fieldDefinition.name)
@@ -252,15 +243,15 @@ class SchemaParser internal constructor(
252243
val extensions = typeExtensions.extensionsOf<EnumTypeExtensionDefinition>(name)
253244
val directives = sdlDirectives.directivesOf(definition, extensions)
254245
val values = definition.withExtensions(typeExtensions).flatMap { it.enumValueDefinitions }
255-
warnRepeated(name, "value", values.map { it.name })
246+
rejectRepeated(name, "value", values)
256247
val builder = GraphQLEnumType.newEnum()
257248
.name(name)
258249
.definition(definition)
259250
.extensionDefinitions(extensions)
260251
.description(getDocumentation(definition, options))
261252
.withSdlDirectives(directives, ENUM)
262253
.apply {
263-
values.distinctBy { it.name }.forEach { valueDefinition ->
254+
values.forEach { valueDefinition ->
264255
val enumName = valueDefinition.name
265256
val enumValue = if (enumClass == null) {
266257
enumName
@@ -306,15 +297,15 @@ class SchemaParser internal constructor(
306297
val extensions = typeExtensions.extensionsOf<InterfaceTypeExtensionDefinition>(interfaceDefinition.name)
307298
val directives = sdlDirectives.directivesOf(interfaceDefinition, extensions)
308299
val fieldDefinitions = interfaceDefinition.withExtensions(typeExtensions).flatMap { it.fieldDefinitions }
309-
warnRepeated(interfaceDefinition.name, "field", fieldDefinitions.map { it.name })
300+
rejectRepeated(interfaceDefinition.name, "field", fieldDefinitions)
310301
val builder = GraphQLInterfaceType.newInterface()
311302
.name(interfaceDefinition.name)
312303
.definition(interfaceDefinition)
313304
.extensionDefinitions(extensions)
314305
.description(getDocumentation(interfaceDefinition, options))
315306
.withSdlDirectives(directives, INTERFACE)
316307
.apply {
317-
fieldDefinitions.distinctBy { it.name }.forEach { fieldDefinition ->
308+
fieldDefinitions.forEach { fieldDefinition ->
318309
field { field -> createField(field, fieldDefinition, inputObjects) }
319310
}
320311
}
@@ -331,7 +322,7 @@ class SchemaParser internal constructor(
331322
private fun createUnionObject(definition: UnionTypeDefinition, types: List<GraphQLObjectType>): GraphQLUnionType {
332323
val extensions = typeExtensions.extensionsOf<UnionTypeExtensionDefinition>(definition.name)
333324
val directives = sdlDirectives.directivesOf(definition, extensions)
334-
warnRepeated(definition.name, "member", definition.withExtensions(typeExtensions).flatMap { it.memberTypes }.map { (it as TypeName).name })
325+
rejectRepeated(definition.name, "member", definition.withExtensions(typeExtensions).flatMap { it.memberTypes }.map { it as TypeName })
335326
val builder = GraphQLUnionType.newUnionType()
336327
.name(definition.name)
337328
.definition(definition)
@@ -373,21 +364,10 @@ class SchemaParser internal constructor(
373364
return leafObjects
374365
}
375366

376-
// TODO throw a SchemaError instead in 15.0.0 (#863), like graphql-java does
377-
private fun warnRepeated(typeName: String, kind: String, names: List<String?>) {
378-
names.groupingBy { it }.eachCount().filterValues { it > 1 }.keys.forEach {
379-
log.warn("Type '$typeName' declares $kind '$it' more than once, only the first one is kept.")
380-
}
381-
}
382-
383-
// TODO throw a SchemaError instead in 15.0.0 (#865), like graphql-java does
384-
private fun warnRepeatedFields(typeName: String, fieldDefinitions: List<NamedNode<*>>) {
385-
fieldDefinitions.groupBy { it.name }.values.filter { it.size > 1 }.forEach { declarations ->
386-
val kept = declarations.last()
387-
val location = kept.sourceLocation.describe()
388-
val which = if (location.isEmpty()) "one of them" else "the one$location"
389-
log.warn("Type '$typeName' declares field '${kept.name}' more than once, only $which is kept.")
390-
}
367+
private fun rejectRepeated(typeName: String, kind: String, declarations: List<NamedNode<*>>) {
368+
val names = mutableSetOf<String?>()
369+
val repeat = declarations.firstOrNull { !names.add(it.name) } ?: return
370+
throw SchemaError("Type '$typeName' declares $kind '${repeat.name}' more than once${repeat.sourceLocation.describe()}.")
391371
}
392372

393373
private fun createField(field: GraphQLFieldDefinition.Builder, fieldDefinition: FieldDefinition, inputObjects: List<GraphQLInputObjectType>): GraphQLFieldDefinition.Builder {

‎src/main/kotlin/graphql/kickstart/tools/SchemaParserOptions.kt‎

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,6 @@ data class SchemaParserOptions internal constructor(
3131
val proxyHandlers: List<ProxyHandler>,
3232
val inputArgumentOptionalDetectOmission: Boolean,
3333
val preferGraphQLResolver: Boolean,
34-
@Deprecated("Will be removed in 15.0.0. Use Introspection.enabledJvmWide(false) for the whole JVM, or put Introspection.INTROSPECTION_DISABLED in the GraphQLContext of the request.")
35-
val introspectionEnabled: Boolean,
3634
val coroutineContextProvider: CoroutineContextProvider,
3735
val typeDefinitionFactories: List<TypeDefinitionFactory>,
3836
val fieldVisibility: GraphqlFieldVisibility?,
@@ -63,7 +61,6 @@ data class SchemaParserOptions internal constructor(
6361
private val proxyHandlers: MutableList<ProxyHandler> = mutableListOf(Spring4AopProxyHandler(), GuiceAopProxyHandler(), JavassistProxyHandler(), WeldProxyHandler())
6462
private var inputArgumentOptionalDetectOmission = false
6563
private var preferGraphQLResolver = false
66-
private var introspectionEnabled = true
6764
private var coroutineContextProvider: CoroutineContextProvider? = null
6865
private var typeDefinitionFactories: MutableList<TypeDefinitionFactory> = mutableListOf(RelayConnectionFactory())
6966
private var fieldVisibility: GraphqlFieldVisibility? = null
@@ -129,11 +126,6 @@ data class SchemaParserOptions internal constructor(
129126
this.proxyHandlers.add(proxyHandler)
130127
}
131128

132-
@Deprecated("Will be removed in 15.0.0. Use Introspection.enabledJvmWide(false) for the whole JVM, or put Introspection.INTROSPECTION_DISABLED in the GraphQLContext of the request.")
133-
fun introspectionEnabled(introspectionEnabled: Boolean) = this.apply {
134-
this.introspectionEnabled = introspectionEnabled
135-
}
136-
137129
fun coroutineContext(context: CoroutineContext) = this.apply {
138130
this.coroutineContextProvider = DefaultCoroutineContextProvider(context)
139131
}
@@ -219,7 +211,6 @@ data class SchemaParserOptions internal constructor(
219211
proxyHandlers,
220212
inputArgumentOptionalDetectOmission,
221213
preferGraphQLResolver,
222-
introspectionEnabled,
223214
coroutineContextProvider,
224215
typeDefinitionFactories,
225216
fieldVisibility,
Lines changed: 2 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,12 @@
11
package graphql.kickstart.tools
22

33
import graphql.GraphQL
4-
import graphql.validation.ValidationError
5-
import graphql.validation.ValidationErrorType
64
import org.junit.Assert.assertEquals
7-
import org.junit.Assert.assertNull
85
import org.junit.Test
96

107
class IntrospectionTest {
118

12-
@Suppress("DEPRECATION")
13-
private fun graphQL(introspectionEnabled: Boolean): GraphQL {
9+
private fun graphQL(): GraphQL {
1410
val schema = SchemaParser.newParser()
1511
.schemaString(
1612
"""
@@ -21,7 +17,6 @@ class IntrospectionTest {
2117
.resolvers(object : GraphQLQueryResolver {
2218
fun name() = "tools"
2319
})
24-
.options(SchemaParserOptions.newOptions().introspectionEnabled(introspectionEnabled).build())
2520
.build()
2621
.makeExecutableSchema()
2722
.assertEveryFieldResolves()
@@ -30,33 +25,10 @@ class IntrospectionTest {
3025

3126
@Test
3227
fun `introspection is enabled by default`() {
33-
val data = assertNoGraphQlErrors(graphQL(introspectionEnabled = true)) {
28+
val data = assertNoGraphQlErrors(graphQL()) {
3429
"{ __schema { queryType { name } } }"
3530
}
3631

3732
assertEquals(mapOf("queryType" to mapOf("name" to "Query")), data["__schema"])
3833
}
39-
40-
@Test
41-
fun `disabling introspection hides the fields of introspection types`() {
42-
val gql = graphQL(introspectionEnabled = false)
43-
44-
listOf("{ __schema { queryType { name } } }", "{ __type(name: \"Query\") { name } }").forEach { query ->
45-
val result = gql.execute(query)
46-
47-
assertNull(result.getData())
48-
assertEquals(
49-
listOf(ValidationErrorType.FieldUndefined),
50-
result.errors.map { (it as ValidationError).validationErrorType })
51-
}
52-
}
53-
54-
@Test
55-
fun `disabling introspection keeps __typename`() {
56-
val data = assertNoGraphQlErrors(graphQL(introspectionEnabled = false)) {
57-
"{ name __typename }"
58-
}
59-
60-
assertEquals(mapOf("name" to "tools", "__typename" to "Query"), data)
61-
}
6234
}

0 commit comments

Comments
 (0)