Skip to content

Commit 6514e0a

Browse files
smyrickdariuszkuc
authored andcommitted
Validate subscription return type (#476)
Subscriptions must return a org.reactivestreams.Publisher for graphql-java to work properly. An exception will now be thrown if any return type of a top level subscription is not a subclass of Publisher Fixes #359
1 parent 8d0c498 commit 6514e0a

File tree

5 files changed

+35
-6
lines changed

5 files changed

+35
-6
lines changed

graphql-kotlin-schema-generator/pom.xml

+3-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515

1616
<properties>
1717
<project.root>${project.basedir}/..</project.root>
18-
<rxjava2.version>2.2.12</rxjava2.version>
18+
19+
<!-- Test Dependencies -->
20+
<rxjava2.version>2.2.14</rxjava2.version>
1921
</properties>
2022

2123
<dependencies>

graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/exceptions/InvalidSubscriptionTypeException.kt

+8-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,13 @@
1616

1717
package com.expediagroup.graphql.exceptions
1818

19+
import com.expediagroup.graphql.generator.extensions.getSimpleName
1920
import kotlin.reflect.KClass
21+
import kotlin.reflect.KFunction
2022

21-
class InvalidSubscriptionTypeException(kClass: KClass<*>) :
22-
GraphQLKotlinException("Schema requires all subscriptions to be public, ${kClass.simpleName} has ${kClass.visibility} visibility modifier")
23+
class InvalidSubscriptionTypeException(kClass: KClass<*>, kFunction: KFunction<*>? = null) :
24+
GraphQLKotlinException(
25+
"Schema requires all subscriptions to be public and return a type of Publisher. " +
26+
"${kClass.simpleName} has ${kClass.visibility} visibility modifier. " +
27+
if (kFunction != null) "The function return type is ${kFunction.returnType.getSimpleName()}" else ""
28+
)

graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/types/SubscriptionBuilder.kt

+6
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ import com.expediagroup.graphql.generator.SchemaGenerator
2222
import com.expediagroup.graphql.generator.TypeBuilder
2323
import com.expediagroup.graphql.generator.extensions.getValidFunctions
2424
import com.expediagroup.graphql.generator.extensions.isNotPublic
25+
import com.expediagroup.graphql.generator.extensions.isSubclassOf
2526
import graphql.schema.GraphQLObjectType
27+
import org.reactivestreams.Publisher
2628

2729
internal class SubscriptionBuilder(generator: SchemaGenerator) : TypeBuilder(generator) {
2830

@@ -42,6 +44,10 @@ internal class SubscriptionBuilder(generator: SchemaGenerator) : TypeBuilder(gen
4244

4345
subscription.kClass.getValidFunctions(config.hooks)
4446
.forEach {
47+
if (it.returnType.isSubclassOf(Publisher::class).not()) {
48+
throw InvalidSubscriptionTypeException(subscription.kClass, it)
49+
}
50+
4551
val function = generator.function(it, config.topLevelNames.subscription, subscription.obj)
4652
val functionFromHook = config.hooks.didGenerateSubscriptionType(it, function)
4753
subscriptionBuilder.field(functionFromHook)

graphql-kotlin-schema-generator/src/test/kotlin/com/expediagroup/graphql/generator/types/SubscriptionBuilderTest.kt

+16-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ internal class SubscriptionBuilderTest : TypeTestHelper() {
4141
}
4242

4343
@Test
44-
fun `give a valid list, it should properly set the top level name`() {
44+
fun `give a valid subscription class, it should properly set the top level name`() {
4545
val builder = SubscriptionBuilder(generator)
4646
val subscriptions = listOf(TopLevelObject(MyPublicTestSubscription()))
4747
every { config.topLevelNames } returns TopLevelNames(subscription = "FooBar")
@@ -60,6 +60,16 @@ internal class SubscriptionBuilderTest : TypeTestHelper() {
6060
}
6161
}
6262

63+
@Test
64+
fun `given a class with a function that does not return Publisher, it should throw an exception`() {
65+
val builder = SubscriptionBuilder(generator)
66+
val subscriptions = listOf(TopLevelObject(MyInvalidSubscriptionClass()))
67+
68+
assertFailsWith(InvalidSubscriptionTypeException::class) {
69+
builder.getSubscriptionObject(subscriptions)
70+
}
71+
}
72+
6373
@Test
6474
fun `given a function that returns a Publisher, it should add it to the schema`() {
6575

@@ -121,6 +131,11 @@ class MyPublicTestSubscription {
121131
fun filterMe(): Publisher<Int> = Flowable.just(2)
122132
}
123133

134+
class MyInvalidSubscriptionClass {
135+
@Suppress("Detekt.FunctionOnlyReturningConstant")
136+
fun number(): Int = 1
137+
}
138+
124139
private class MyPrivateTestSubscription {
125140
fun counter(): Publisher<Int> = Flowable.just(3)
126141
}

pom.xml

+2-2
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,10 @@
6363

6464
<!-- Dependency Versions -->
6565
<graphql-java.version>13.0</graphql-java.version>
66-
<jackson-module-kotlin.version>2.10.0</jackson-module-kotlin.version>
66+
<jackson-module-kotlin.version>2.10.1</jackson-module-kotlin.version>
6767
<kotlin.version>1.3.50</kotlin.version>
6868
<kotlin-coroutines.version>1.3.2</kotlin-coroutines.version>
69-
<classgraph.version>4.8.52</classgraph.version>
69+
<classgraph.version>4.8.53</classgraph.version>
7070
<spring-boot.version>2.2.1.RELEASE</spring-boot.version>
7171

7272
<!-- Test Dependency Versions -->

0 commit comments

Comments
 (0)