Skip to content

Commit d3ba558

Browse files
smyrickdariuszkuc
authored andcommitted
Upgrade to graphql-java 14 (#568)
* First pass at graphql-java 14 * Fix regex for new graphql description format * Fix integration tests * Add multiline comment tests to federated SDL * Remove deprecated printer option GraphQL Java deprecated the descriptionsAsHashComments so instead of including it we should just not add it until there is a need as it will eventually be removed
1 parent 82a982b commit d3ba558

File tree

26 files changed

+248
-224
lines changed

26 files changed

+248
-224
lines changed

examples/spring/src/test/kotlin/com/expediagroup/graphql/examples/query/PolymorphicQueryIT.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ class PolymorphicQueryIT(@Autowired private val testClient: WebTestClient) {
8282
.exchange()
8383
.expectStatus().isOk
8484
.verifyError("Validation error of type WrongType: " +
85-
"argument 'type' with value 'EnumValue{name='$unknownType'}' is not a valid 'AnimalType' @ 'animal'")
85+
"argument 'type' with value 'EnumValue{name='$unknownType'}' is not a valid 'AnimalType' - " +
86+
"Expected enum literal value not in allowable values - 'EnumValue{name='HELLO'}'. @ 'animal'")
8687
}
8788

8889
@Test

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ org.gradle.parallel=true
99
kotlinVersion = 1.3.50
1010
kotlinCoroutinesVersion = 1.3.2
1111

12-
graphQLJavaVersion = 13.0
12+
graphQLJavaVersion = 14.0
1313
jacksonVersion = 2.10.1
1414
springBootVersion = 2.2.1.RELEASE
1515
classGraphVersion = 4.8.53

graphql-kotlin-federation/src/main/kotlin/com/expediagroup/graphql/federation/FederatedSchemaGeneratorHooks.kt

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,14 @@
1717
package com.expediagroup.graphql.federation
1818

1919
import com.expediagroup.graphql.annotations.GraphQLName
20+
import com.expediagroup.graphql.directives.DEPRECATED_DIRECTIVE_NAME
2021
import com.expediagroup.graphql.extensions.print
22+
import com.expediagroup.graphql.federation.directives.EXTENDS_DIRECTIVE_NAME
23+
import com.expediagroup.graphql.federation.directives.EXTERNAL_DIRECTIVE_NAME
2124
import com.expediagroup.graphql.federation.directives.FieldSet
2225
import com.expediagroup.graphql.federation.directives.KEY_DIRECTIVE_NAME
26+
import com.expediagroup.graphql.federation.directives.PROVIDES_DIRECTIVE_NAME
27+
import com.expediagroup.graphql.federation.directives.REQUIRES_DIRECTIVE_NAME
2328
import com.expediagroup.graphql.federation.directives.extendsDirectiveType
2429
import com.expediagroup.graphql.federation.execution.EntityResolver
2530
import com.expediagroup.graphql.federation.execution.FederatedTypeRegistry
@@ -34,23 +39,26 @@ import graphql.TypeResolutionEnvironment
3439
import graphql.schema.DataFetcher
3540
import graphql.schema.FieldCoordinates
3641
import graphql.schema.GraphQLCodeRegistry
42+
import graphql.schema.GraphQLDirective
3743
import graphql.schema.GraphQLObjectType
3844
import graphql.schema.GraphQLSchema
3945
import graphql.schema.GraphQLType
46+
import java.util.function.Predicate
4047
import kotlin.reflect.KType
4148
import kotlin.reflect.full.findAnnotation
4249

4350
/**
4451
* Hooks for generating federated GraphQL schema.
4552
*/
4653
open class FederatedSchemaGeneratorHooks(private val federatedTypeRegistry: FederatedTypeRegistry) : SchemaGeneratorHooks {
47-
private val directiveDefinitionRegex = "(^#.+$[\\r\\n])?^directive @\\w+.+$[\\r\\n]*".toRegex(setOf(RegexOption.MULTILINE, RegexOption.IGNORE_CASE))
48-
private val customDirectivesRegex = "\\s*@(?!extends)(?!external)(?!key)(?!provides)(?!requires)(?!deprecated)\\w+(?:\\(.*(?=\\))\\))?".toRegex(
49-
setOf(RegexOption.MULTILINE, RegexOption.IGNORE_CASE))
50-
private val scalarDefinitionRegex = "(^#.+$[\\r\\n])?^scalar (_FieldSet|_Any)$[\\r\\n]*".toRegex(setOf(RegexOption.MULTILINE, RegexOption.IGNORE_CASE))
54+
private val directiveDefinitionRegex = "(^\".+\"$[\\r\\n])?^directive @\\w+.+\$[\\r\\n]*".toRegex(setOf(RegexOption.MULTILINE, RegexOption.IGNORE_CASE))
55+
private val scalarDefinitionRegex = "(^\".+\"$[\\r\\n])?^scalar (_FieldSet|_Any)$[\\r\\n]*".toRegex(setOf(RegexOption.MULTILINE, RegexOption.IGNORE_CASE))
5156
private val emptyQueryRegex = "^type Query \\{$\\s+^\\}$\\s+".toRegex(setOf(RegexOption.MULTILINE, RegexOption.IGNORE_CASE))
5257
private val validator = FederatedSchemaValidator()
5358

59+
private val directivesToInclude = listOf(EXTENDS_DIRECTIVE_NAME, EXTERNAL_DIRECTIVE_NAME, KEY_DIRECTIVE_NAME, PROVIDES_DIRECTIVE_NAME, REQUIRES_DIRECTIVE_NAME, DEPRECATED_DIRECTIVE_NAME)
60+
private val customDirectivePredicate: Predicate<GraphQLDirective> = Predicate { directivesToInclude.contains(it.name) }
61+
5462
override fun willGenerateGraphQLType(type: KType): GraphQLType? = when (type.classifier) {
5563
FieldSet::class -> FIELD_SET_SCALAR_TYPE
5664
else -> null
@@ -79,14 +87,13 @@ open class FederatedSchemaGeneratorHooks(private val federatedTypeRegistry: Fede
7987
* - any custom directives
8088
* - new federated scalars
8189
*/
82-
val sdl = originalSchema.print(includeDefaultSchemaDefinition = false)
90+
val sdl = originalSchema.print(includeDefaultSchemaDefinition = false, includeDirectivesFilter = customDirectivePredicate)
8391
/**
84-
* TODO: this can be simplified once this is solved: apollographql/apollo-server#3334
92+
* TODO: this can be simplified once this is solved: https://github.com/apollographql/apollo-server/issues/3334
8593
*/
8694
.replace(directiveDefinitionRegex, "")
8795
.replace(scalarDefinitionRegex, "")
8896
.replace(emptyQueryRegex, "")
89-
.replace(customDirectivesRegex, "")
9097
.trim()
9198
federatedCodeRegistry.dataFetcher(FieldCoordinates.coordinates(originalQuery.name, SERVICE_FIELD_DEFINITION.name), DataFetcher { _Service(sdl) })
9299

graphql-kotlin-federation/src/test/kotlin/com/expediagroup/graphql/federation/FederatedSchemaGeneratorTest.kt

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -32,21 +32,36 @@ private const val FEDERATED_SDL = """schema {
3232
query: Query
3333
}
3434
35-
#Marks target field as external meaning it will be resolved by federated schema
35+
"Directs the executor to include this field or fragment only when the `if` argument is true"
36+
directive @include(
37+
"Included when true."
38+
if: Boolean!
39+
) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
40+
41+
"Directs the executor to skip this field or fragment when the `if`'argument is true."
42+
directive @skip(
43+
"Skipped when true."
44+
if: Boolean!
45+
) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
46+
47+
"Marks target field as external meaning it will be resolved by federated schema"
3648
directive @external on FIELD_DEFINITION
3749
38-
#Marks target object as extending part of the federated schema
50+
"Marks target object as extending part of the federated schema"
3951
directive @extends on OBJECT | INTERFACE
4052
41-
#Specifies the base type field set that will be selectable by the gateway
53+
"Specifies the base type field set that will be selectable by the gateway"
4254
directive @provides(fields: _FieldSet!) on FIELD_DEFINITION
4355
56+
"Marks the target field/enum value as deprecated"
57+
directive @deprecated(reason: String = "No longer supported") on FIELD_DEFINITION | ENUM_VALUE
58+
4459
directive @custom on SCHEMA | SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION
4560
46-
#Space separated list of primary keys needed to access federated object
61+
"Space separated list of primary keys needed to access federated object"
4762
directive @key(fields: _FieldSet!) on OBJECT | INTERFACE
4863
49-
#Specifies required input field set from the base type for a resolver
64+
"Specifies required input field set from the base type for a resolver"
5065
directive @requires(fields: _FieldSet!) on FIELD_DEFINITION
5166
5267
interface Product @extends @key(fields : "id") {
@@ -64,15 +79,20 @@ type Book implements Product @extends @key(fields : "id") {
6479
weight: Float! @external
6580
}
6681
82+
type CustomScalar {
83+
value: String!
84+
}
85+
6786
type Query @extends {
68-
#Union of all types that use the @key directive, including both types native to the schema and extended types
87+
"Union of all types that use the @key directive, including both types native to the schema and extended types"
6988
_entities(representations: [_Any!]!): [_Entity]!
7089
_service: _Service
7190
}
7291
7392
type Review {
7493
body: String! @custom
7594
content: String @deprecated(reason : "no longer supported, replace with use Review.body instead")
95+
customScalar: CustomScalar!
7696
id: String!
7797
}
7898
@@ -85,20 +105,11 @@ type _Service {
85105
sdl: String!
86106
}
87107
88-
#Federation scalar type used to represent any external entities passed to _entities query.
108+
"Federation scalar type used to represent any external entities passed to _entities query."
89109
scalar _Any
90110
91-
#Federation type representing set of fields
92-
scalar _FieldSet
93-
94-
#Directs the executor to include this field or fragment only when the `if` argument is true
95-
directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
96-
97-
#Directs the executor to skip this field or fragment when the `if`'argument is true.
98-
directive @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
99-
100-
#Marks the target field/enum value as deprecated
101-
directive @deprecated(reason: String = "No longer supported") on FIELD_DEFINITION | ENUM_VALUE"""
111+
"Federation type representing set of fields"
112+
scalar _FieldSet"""
102113

103114
class FederatedSchemaGeneratorTest {
104115

graphql-kotlin-federation/src/test/kotlin/com/expediagroup/graphql/federation/data/queries/federated/Product.kt

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package com.expediagroup.graphql.federation.data.queries.federated
1818

19+
import com.expediagroup.graphql.annotations.GraphQLDescription
1920
import com.expediagroup.graphql.annotations.GraphQLDirective
2021
import com.expediagroup.graphql.annotations.GraphQLIgnore
2122
import com.expediagroup.graphql.federation.directives.ExtendsDirective
@@ -59,7 +60,7 @@ class Book(
5960
@ExternalDirective
6061
var weight: Double by Delegates.notNull()
6162

62-
override fun reviews(): List<Review> = listOf(Review("parent-$id", "Dummy Review $id"))
63+
override fun reviews(): List<Review> = listOf(Review(id = "parent-$id", body = "Dummy Review $id", content = null, customScalar = CustomScalar("foo")))
6364

6465
@RequiresDirective(FieldSet("weight"))
6566
fun shippingCost(): String = "$${weight * 9.99}"
@@ -98,7 +99,8 @@ type Review {
9899
data class Review(
99100
val id: String,
100101
@CustomDirective val body: String,
101-
@Deprecated(message = "no longer supported", replaceWith = ReplaceWith("use Review.body instead")) val content: String? = null
102+
@Deprecated(message = "no longer supported", replaceWith = ReplaceWith("use Review.body instead")) val content: String? = null,
103+
val customScalar: CustomScalar
102104
)
103105

104106
/*
@@ -115,4 +117,11 @@ data class User(
115117
)
116118

117119
@GraphQLDirective(name = "custom")
120+
@GraphQLDescription("""
121+
This is a multi-line comment on a custom directive.
122+
This should still work multiline and double quotes (") in the description.
123+
Line 3.
124+
""")
118125
annotation class CustomDirective
126+
127+
class CustomScalar(val value: String)

graphql-kotlin-federation/src/test/kotlin/com/expediagroup/graphql/federation/execution/ServiceQueryResolverTest.kt

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,20 @@ package com.expediagroup.graphql.federation.execution
1919
import com.expediagroup.graphql.TopLevelObject
2020
import com.expediagroup.graphql.federation.FederatedSchemaGeneratorConfig
2121
import com.expediagroup.graphql.federation.FederatedSchemaGeneratorHooks
22+
import com.expediagroup.graphql.federation.data.queries.federated.CustomScalar
2223
import com.expediagroup.graphql.federation.data.queries.simple.NestedQuery
2324
import com.expediagroup.graphql.federation.data.queries.simple.SimpleQuery
2425
import com.expediagroup.graphql.federation.toFederatedSchema
2526
import graphql.ExecutionInput
2627
import graphql.GraphQL
28+
import graphql.language.StringValue
29+
import graphql.schema.Coercing
30+
import graphql.schema.CoercingParseValueException
31+
import graphql.schema.GraphQLScalarType
32+
import graphql.schema.GraphQLType
2733
import org.junit.jupiter.api.Test
34+
import kotlin.reflect.KClass
35+
import kotlin.reflect.KType
2836
import kotlin.test.assertEquals
2937
import kotlin.test.assertNotNull
3038

@@ -46,13 +54,21 @@ type Book implements Product @extends @key(fields : "id") {
4654
type Review {
4755
body: String!
4856
content: String @deprecated(reason : "no longer supported, replace with use Review.body instead")
57+
customScalar: CustomScalar!
4958
id: String!
5059
}
5160
5261
type User @extends @key(fields : "userId") {
5362
name: String! @external
5463
userId: Int! @external
55-
}"""
64+
}
65+
66+
""${'"'}
67+
This is a multi-line comment on a custom scalar.
68+
This should still work multiline and double quotes (") in the description.
69+
Line 3.
70+
""${'"'}
71+
scalar CustomScalar"""
5672

5773
const val BASE_SERVICE_SDL = """
5874
type Query {
@@ -69,11 +85,38 @@ type SelfReferenceObject {
6985

7086
class ServiceQueryResolverTest {
7187

88+
class CustomScalarFederatedHooks : FederatedSchemaGeneratorHooks(FederatedTypeRegistry()) {
89+
override fun willGenerateGraphQLType(type: KType): GraphQLType? = when (type.classifier as? KClass<*>) {
90+
CustomScalar::class -> graphqlCustomScalar
91+
else -> super.willGenerateGraphQLType(type)
92+
}
93+
94+
private val graphqlCustomScalar = GraphQLScalarType.newScalar()
95+
.name("CustomScalar")
96+
.description("""
97+
This is a multi-line comment on a custom scalar.
98+
This should still work multiline and double quotes (") in the description.
99+
Line 3.
100+
""".trimIndent())
101+
.coercing(CustomScalarCoercing()).build()
102+
103+
private class CustomScalarCoercing : Coercing<CustomScalar, String> {
104+
override fun parseValue(input: Any?): CustomScalar = CustomScalar(serialize(input))
105+
106+
override fun parseLiteral(input: Any?): CustomScalar? {
107+
val customValue = (input as? StringValue)?.value ?: throw CoercingParseValueException("CustomScalar value is null")
108+
return CustomScalar(customValue)
109+
}
110+
111+
override fun serialize(dataFetcherResult: Any?): String = dataFetcherResult.toString()
112+
}
113+
}
114+
72115
@Test
73116
fun `verify can retrieve SDL using _service query`() {
74117
val config = FederatedSchemaGeneratorConfig(
75118
supportedPackages = listOf("com.expediagroup.graphql.federation.data.queries.federated"),
76-
hooks = FederatedSchemaGeneratorHooks(FederatedTypeRegistry())
119+
hooks = CustomScalarFederatedHooks()
77120
)
78121

79122
val schema = toFederatedSchema(config = config)

graphql-kotlin-federation/src/test/kotlin/com/expediagroup/graphql/federation/types/ServiceTest.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package com.expediagroup.graphql.federation.types
1818

19+
import graphql.Scalars.GraphQLString
1920
import graphql.schema.GraphQLNonNull
2021
import graphql.schema.GraphQLObjectType
2122
import org.junit.jupiter.api.Test
@@ -40,6 +41,6 @@ internal class ServiceTest {
4041

4142
val fieldType = serviceObject.fieldDefinitions.first().type as? GraphQLNonNull
4243
assertNotNull(fieldType)
43-
assertEquals(expected = "String", actual = fieldType.wrappedType.name)
44+
assertEquals(expected = GraphQLString, actual = fieldType.wrappedType)
4445
}
4546
}

graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/directives/KotlinDirectiveWiringFactory.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import graphql.schema.GraphQLCodeRegistry
2323
import graphql.schema.GraphQLDirective
2424
import graphql.schema.GraphQLDirectiveContainer
2525
import graphql.schema.GraphQLFieldDefinition
26-
import graphql.schema.GraphQLType
26+
import graphql.schema.GraphQLSchemaElement
2727

2828
/**
2929
* Wiring factory that is used to provide the directives.
@@ -35,10 +35,10 @@ open class KotlinDirectiveWiringFactory(
3535
/**
3636
* Wire up the directive based on the GraphQL type.
3737
*/
38-
fun onWire(graphQLType: GraphQLType, coordinates: FieldCoordinates? = null, codeRegistry: GraphQLCodeRegistry.Builder? = null): GraphQLType {
39-
if (graphQLType !is GraphQLDirectiveContainer) return graphQLType
38+
fun onWire(graphQLSchemaElement: GraphQLSchemaElement, coordinates: FieldCoordinates? = null, codeRegistry: GraphQLCodeRegistry.Builder? = null): GraphQLSchemaElement {
39+
if (graphQLSchemaElement !is GraphQLDirectiveContainer) return graphQLSchemaElement
4040

41-
return wireDirectives(graphQLType, coordinates, graphQLType.getAllDirectives(), codeRegistry)
41+
return wireDirectives(graphQLSchemaElement, coordinates, graphQLSchemaElement.getAllDirectives(), codeRegistry)
4242
}
4343

4444
/**

graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/exceptions/CouldNotCastGraphQLType.kt renamed to graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/exceptions/CouldNotCastGraphQLSchemaElement.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@
1616

1717
package com.expediagroup.graphql.exceptions
1818

19-
import graphql.schema.GraphQLType
19+
import graphql.schema.GraphQLSchemaElement
2020
import kotlin.reflect.KClass
2121

2222
/**
23-
* Thrown when the casting a GraphQLType to some parent type is invalid
23+
* Thrown when the casting a [GraphQLSchemaElement] to some parent type is invalid
2424
*/
25-
class CouldNotCastGraphQLType(type: GraphQLType, kClass: KClass<*>) :
26-
GraphQLKotlinException("Could not cast GraphQLType $type to $kClass")
25+
class CouldNotCastGraphQLSchemaElement(graphQLSchemaElement: GraphQLSchemaElement, kClass: KClass<*>) :
26+
GraphQLKotlinException("Could not cast GraphQLSchemaElement $graphQLSchemaElement to $kClass")

0 commit comments

Comments
 (0)