Skip to content

Commit 11f2e9a

Browse files
smyrickdariuszkuc
authored andcommitted
feat: move default implementations to interface (#68)
* feat: move default implementations to interface * fix: update unit tests
1 parent f8b68d8 commit 11f2e9a

File tree

10 files changed

+53
-79
lines changed

10 files changed

+53
-79
lines changed

example/src/main/kotlin/com.expedia.graphql.sample/extension/CustomSchemaGeneratorHooks.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package com.expedia.graphql.sample.extension
22

33
import com.expedia.graphql.sample.validation.DataFetcherExecutionValidator
44
import com.expedia.graphql.schema.hooks.DataFetcherExecutionPredicate
5-
import com.expedia.graphql.schema.hooks.NoopSchemaGeneratorHooks
5+
import com.expedia.graphql.schema.hooks.SchemaGeneratorHooks
66
import graphql.language.StringValue
77
import graphql.schema.Coercing
88
import graphql.schema.GraphQLScalarType
@@ -15,7 +15,7 @@ import kotlin.reflect.KType
1515
/**
1616
* Schema generator hook that adds additional scalar types.
1717
*/
18-
class CustomSchemaGeneratorHooks(validator: Validator) : NoopSchemaGeneratorHooks() {
18+
class CustomSchemaGeneratorHooks(validator: Validator) : SchemaGeneratorHooks {
1919

2020
/**
2121
* Register additional GraphQL scalar types.

src/main/kotlin/com/expedia/graphql/schema/extensions/annotationExtensions.kt

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import com.expedia.graphql.annotations.GraphQLID
55
import com.expedia.graphql.annotations.GraphQLIgnore
66
import com.expedia.graphql.schema.exceptions.CouldNotGetNameOfAnnotationException
77
import com.expedia.graphql.schema.generator.types.defaultGraphQLScalars
8+
import com.expedia.graphql.schema.hooks.SchemaGeneratorHooks
89
import com.google.common.base.CaseFormat
910
import graphql.schema.GraphQLArgument
1011
import graphql.schema.GraphQLDirective
@@ -36,8 +37,9 @@ private fun KAnnotatedElement.listOfDirectives(): List<String> {
3637

3738
return this.annotations.asSequence()
3839
.mapNotNull { it.getDirectiveInfo() }
39-
.map { when {
40-
it.effectiveName != null -> "@${it.effectiveName}"
40+
.map {
41+
when {
42+
it.effectiveName.isNullOrEmpty().not() -> "@${it.effectiveName}"
4143
else -> null
4244
}
4345
}
@@ -69,14 +71,14 @@ private fun Annotation.getDirectiveInfo(): DirectiveInfo? {
6971
}
7072
}
7173

72-
internal fun KAnnotatedElement.directives() =
74+
internal fun KAnnotatedElement.directives(hooks: SchemaGeneratorHooks) =
7375
this.annotations.asSequence()
7476
.mapNotNull { it.getDirectiveInfo() }
75-
.map { it.getGraphQLDirective() }
77+
.map { it.getGraphQLDirective(hooks) }
7678
.toList()
7779

7880
@Throws(CouldNotGetNameOfAnnotationException::class)
79-
private fun DirectiveInfo.getGraphQLDirective(): GraphQLDirective {
81+
private fun DirectiveInfo.getGraphQLDirective(hooks: SchemaGeneratorHooks): GraphQLDirective {
8082
val kClass: KClass<out DirectiveAnnotation> = this.annotation.annotationClass
8183
val builder = GraphQLDirective.newDirective()
8284
val name: String = this.effectiveName ?: throw CouldNotGetNameOfAnnotationException(kClass)
@@ -87,7 +89,7 @@ private fun DirectiveInfo.getGraphQLDirective(): GraphQLDirective {
8789
.validLocations(*this.annotation.locations)
8890
.description(this.annotation.description)
8991

90-
kClass.getValidFunctions().forEach { kFunction ->
92+
kClass.getValidFunctions(hooks).forEach { kFunction ->
9193
val propertyName = kFunction.name
9294
val value = kFunction.call(kClass)
9395
@Suppress("Detekt.UnsafeCast")

src/main/kotlin/com/expedia/graphql/schema/generator/SchemaGenerator.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ internal class SchemaGenerator(
120120
builder.deprecate(it)
121121
}
122122

123-
fn.directives().forEach {
123+
fn.directives(config.hooks).forEach {
124124
builder.withDirective(it)
125125
state.directives.add(it)
126126
}
@@ -221,7 +221,7 @@ internal class SchemaGenerator(
221221
builder.name(kClass.simpleName)
222222
builder.description(kClass.graphQLDescription())
223223

224-
kClass.directives().forEach {
224+
kClass.directives(config.hooks).forEach {
225225
builder.withDirective(it)
226226
state.directives.add(it)
227227
}
Lines changed: 3 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,7 @@
11
package com.expedia.graphql.schema.hooks
22

3-
import graphql.schema.DataFetcher
4-
import graphql.schema.GraphQLFieldDefinition
5-
import graphql.schema.GraphQLSchema
6-
import graphql.schema.GraphQLType
7-
import java.util.concurrent.CompletableFuture
8-
import kotlin.reflect.KFunction
9-
import kotlin.reflect.KProperty
10-
import kotlin.reflect.KType
11-
123
/**
13-
* Default hooks that do not override or set anything.
14-
*
15-
* To set your own custom hooks, it is easier to extend this class instead of SchemaGeneratorHooks
16-
* and just override the methods you need.
4+
* Default hooks that do not override or set anything. Only used internally.
5+
* If you don't need hooks, the configuration will default to these.
176
*/
18-
open class NoopSchemaGeneratorHooks : SchemaGeneratorHooks {
19-
20-
override fun willBuildSchema(builder: GraphQLSchema.Builder): GraphQLSchema.Builder = builder
21-
22-
override fun willGenerateGraphQLType(type: KType): GraphQLType? = null
23-
24-
override fun willResolveMonad(type: KType): KType =
25-
if (type.classifier == CompletableFuture::class) {
26-
type.arguments.firstOrNull()?.type ?: type
27-
} else {
28-
type
29-
}
30-
31-
override fun isValidProperty(property: KProperty<*>) = true
32-
33-
override fun isValidFunction(function: KFunction<*>) = true
34-
35-
override fun didGenerateGraphQLType(type: KType, generatedType: GraphQLType) = Unit
36-
37-
override fun didGenerateDataFetcher(function: KFunction<*>, dataFetcher: DataFetcher<*>) = dataFetcher
38-
39-
override fun didGenerateQueryType(function: KFunction<*>, fieldDefinition: GraphQLFieldDefinition) = fieldDefinition
40-
41-
override fun didGenerateMutationType(function: KFunction<*>, fieldDefinition: GraphQLFieldDefinition) = fieldDefinition
42-
43-
override val dataFetcherExecutionPredicate: DataFetcherExecutionPredicate? = null
44-
}
7+
internal class NoopSchemaGeneratorHooks : SchemaGeneratorHooks

src/main/kotlin/com/expedia/graphql/schema/hooks/SchemaGeneratorHooks.kt

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import graphql.schema.DataFetcher
44
import graphql.schema.GraphQLFieldDefinition
55
import graphql.schema.GraphQLSchema
66
import graphql.schema.GraphQLType
7+
import java.util.concurrent.CompletableFuture
78
import kotlin.reflect.KFunction
89
import kotlin.reflect.KProperty
910
import kotlin.reflect.KType
@@ -18,56 +19,65 @@ interface SchemaGeneratorHooks {
1819
* Called before the final GraphQL schema is built.
1920
* This doesn't prevent the called from rebuilding the final schema using java-graphql's functionality
2021
*/
21-
fun willBuildSchema(builder: GraphQLSchema.Builder): GraphQLSchema.Builder
22+
fun willBuildSchema(builder: GraphQLSchema.Builder): GraphQLSchema.Builder = builder
2223

2324
/**
2425
* Called before using reflection to generate the graphql object type for the given KType.
2526
* This allows supporting objects that the caller does not want to use reflection on for special handling
2627
*/
27-
fun willGenerateGraphQLType(type: KType): GraphQLType?
28+
@Suppress("Detekt.FunctionOnlyReturningConstant")
29+
fun willGenerateGraphQLType(type: KType): GraphQLType? = null
2830

2931
/**
3032
* Called before resolving a Monad or Future type to its wrapped KType.
3133
* This allows for a custom resolver on how to extract the wrapped value.
3234
*/
33-
fun willResolveMonad(type: KType): KType
35+
fun willResolveMonad(type: KType): KType =
36+
if (type.classifier == CompletableFuture::class) {
37+
type.arguments.firstOrNull()?.type ?: type
38+
} else {
39+
type
40+
}
3441

3542
/**
3643
* Called when looking at the KClass properties to determine if it valid for adding to the generated schema.
3744
* If any filter returns false, it is rejected.
3845
*/
39-
fun isValidProperty(property: KProperty<*>): Boolean
46+
@Suppress("Detekt.FunctionOnlyReturningConstant")
47+
fun isValidProperty(property: KProperty<*>): Boolean = true
4048

4149
/**
4250
* Called when looking at the KClass functions to determine if it valid for adding to the generated schema.
4351
* If any filter returns false, it is rejected.
4452
*/
45-
fun isValidFunction(function: KFunction<*>): Boolean
53+
@Suppress("Detekt.FunctionOnlyReturningConstant")
54+
fun isValidFunction(function: KFunction<*>): Boolean = true
4655

4756
/**
4857
* Called after wrapping the type based on nullity but before adding the generated type to the schema
4958
*/
50-
fun didGenerateGraphQLType(type: KType, generatedType: GraphQLType)
59+
fun didGenerateGraphQLType(type: KType, generatedType: GraphQLType) = Unit
5160

5261
/**
5362
* Called after converting the function to a data fetcher allowing wrapping the fetcher to modify data or instrument it.
5463
* This is more useful than the graphql.execution.instrumentation.Instrumentation as you have the function type here
5564
*/
56-
fun didGenerateDataFetcher(function: KFunction<*>, dataFetcher: DataFetcher<*>): DataFetcher<*>
65+
fun didGenerateDataFetcher(function: KFunction<*>, dataFetcher: DataFetcher<*>): DataFetcher<*> = dataFetcher
5766

5867
/**
5968
* Called after converting the function to a field definition but before adding to the schema to allow customization
6069
*/
61-
fun didGenerateQueryType(function: KFunction<*>, fieldDefinition: GraphQLFieldDefinition): GraphQLFieldDefinition
70+
fun didGenerateQueryType(function: KFunction<*>, fieldDefinition: GraphQLFieldDefinition): GraphQLFieldDefinition = fieldDefinition
6271

6372
/**
6473
* Called after converting the function to a field definition but before adding to the schema to allow customization
6574
*/
66-
fun didGenerateMutationType(function: KFunction<*>, fieldDefinition: GraphQLFieldDefinition): GraphQLFieldDefinition
75+
fun didGenerateMutationType(function: KFunction<*>, fieldDefinition: GraphQLFieldDefinition): GraphQLFieldDefinition = fieldDefinition
6776

6877
/**
6978
* Execute a predicate on each function parameters after their deserialization
7079
* If the execution is unsuccessful the `onFailure` method will be invoked
7180
*/
7281
val dataFetcherExecutionPredicate: DataFetcherExecutionPredicate?
82+
get() = null
7383
}

src/test/kotlin/com/expedia/graphql/schema/dataFetchers/DataFetchPredicateTests.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import com.expedia.graphql.TopLevelObjectDef
44
import com.expedia.graphql.schema.Parameter
55
import com.expedia.graphql.schema.getTestSchemaConfigWithHooks
66
import com.expedia.graphql.schema.hooks.DataFetcherExecutionPredicate
7-
import com.expedia.graphql.schema.hooks.NoopSchemaGeneratorHooks
7+
import com.expedia.graphql.schema.hooks.SchemaGeneratorHooks
88
import com.expedia.graphql.toSchema
99
import graphql.ExceptionWhileDataFetching
1010
import graphql.GraphQL
@@ -57,7 +57,7 @@ class QueryWithValidations {
5757

5858
data class Person(val name: String, val age: Int)
5959

60-
class PredicateHooks : NoopSchemaGeneratorHooks() {
60+
class PredicateHooks : SchemaGeneratorHooks {
6161
override val dataFetcherExecutionPredicate: DataFetcherExecutionPredicate? = TestDataFetcherPredicate()
6262
}
6363

src/test/kotlin/com/expedia/graphql/schema/extensions/KClassExtensionsTest.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package com.expedia.graphql.schema.extensions
22

3-
import com.expedia.graphql.schema.hooks.NoopSchemaGeneratorHooks
3+
import com.expedia.graphql.schema.hooks.SchemaGeneratorHooks
44
import org.junit.jupiter.api.Test
55
import kotlin.reflect.KFunction
66
import kotlin.reflect.KProperty
@@ -21,7 +21,7 @@ class KClassExtensionsTest {
2121
private fun privateTestFunction() = "private function"
2222
}
2323

24-
class FilterHooks : NoopSchemaGeneratorHooks() {
24+
class FilterHooks : SchemaGeneratorHooks {
2525
override fun isValidProperty(property: KProperty<*>) =
2626
property.name.contains("filteredProperty").not()
2727

src/test/kotlin/com/expedia/graphql/schema/generator/SchemaGeneratorAsyncTests.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package com.expedia.graphql.schema.generator
22

33
import com.expedia.graphql.TopLevelObjectDef
44
import com.expedia.graphql.schema.getTestSchemaConfigWithHooks
5-
import com.expedia.graphql.schema.hooks.NoopSchemaGeneratorHooks
5+
import com.expedia.graphql.schema.hooks.SchemaGeneratorHooks
66
import com.expedia.graphql.schema.testSchemaConfig
77
import com.expedia.graphql.toSchema
88
import graphql.schema.GraphQLNonNull
@@ -16,7 +16,7 @@ import kotlin.test.assertEquals
1616

1717
class SchemaGeneratorAsyncTests {
1818

19-
private class MonadHooks : NoopSchemaGeneratorHooks() {
19+
private class MonadHooks : SchemaGeneratorHooks {
2020
override fun willResolveMonad(type: KType): KType = when (type.classifier) {
2121
Observable::class, Single::class, Maybe::class -> type.arguments.firstOrNull()?.type
2222
else -> type

src/test/kotlin/com/expedia/graphql/schema/generator/SchemaGeneratorTest.kt

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,13 @@ import graphql.GraphQL
1313
import graphql.Scalars
1414
import graphql.schema.GraphQLNonNull
1515
import graphql.schema.GraphQLObjectType
16-
import org.junit.jupiter.api.Assertions.assertNull
17-
import org.junit.jupiter.api.Assertions.assertThrows
1816
import java.net.CookieManager
1917
import java.util.UUID
2018
import kotlin.test.Test
2119
import kotlin.test.assertEquals
2220
import kotlin.test.assertFailsWith
2321
import kotlin.test.assertNotNull
22+
import kotlin.test.assertNull
2423
import kotlin.test.assertTrue
2524

2625
@Suppress("Detekt.UnusedPrivateMember",
@@ -209,21 +208,21 @@ class SchemaGeneratorTest {
209208

210209
@Test
211210
fun `SchemaGenerator throws when encountering java stdlib`() {
212-
assertThrows(RuntimeException::class.java) {
211+
assertFailsWith(RuntimeException::class) {
213212
toSchema(listOf(TopLevelObjectDef(QueryWithJavaClass())), config = testSchemaConfig)
214213
}
215214
}
216215

217216
@Test
218217
fun `SchemaGenerator throws when encountering conflicting types`() {
219-
assertThrows(ConflictingTypesException::class.java) {
218+
assertFailsWith(ConflictingTypesException::class) {
220219
toSchema(queries = listOf(TopLevelObjectDef(QueryWithConflictingTypes())), config = testSchemaConfig)
221220
}
222221
}
223222

224223
@Test
225224
fun `SchemaGenerator should throw exception if no queries and no mutations are specified`() {
226-
assertThrows(InvalidSchemaException::class.java) {
225+
assertFailsWith(InvalidSchemaException::class) {
227226
toSchema(emptyList(), emptyList(), config = testSchemaConfig)
228227
}
229228
}
@@ -260,7 +259,7 @@ class SchemaGeneratorTest {
260259

261260
@Test
262261
fun `SchemaGenerator throws an exception for invalid GraphQLID`() {
263-
val exception = assertThrows(IllegalArgumentException::class.java) {
262+
val exception = assertFailsWith(IllegalArgumentException::class) {
264263
toSchema(queries = listOf(TopLevelObjectDef(QueryWithInvalidId())), config = testSchemaConfig)
265264
}
266265

src/test/kotlin/com/expedia/graphql/schema/hooks/SchemaGeneratorHooksTest.kt

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class SchemaGeneratorHooksTest {
2626

2727
@Test
2828
fun `calls hook before schema is built`() {
29-
class MockSchemaGeneratorHooks : NoopSchemaGeneratorHooks() {
29+
class MockSchemaGeneratorHooks : SchemaGeneratorHooks {
3030
var willBuildSchemaCalled = false
3131
override fun willBuildSchema(builder: GraphQLSchema.Builder): GraphQLSchema.Builder {
3232
willBuildSchemaCalled = true
@@ -46,7 +46,7 @@ class SchemaGeneratorHooksTest {
4646

4747
@Test
4848
fun `calls hook before generating object type`() {
49-
class MockSchemaGeneratorHooks : NoopSchemaGeneratorHooks() {
49+
class MockSchemaGeneratorHooks : SchemaGeneratorHooks {
5050
var willGenerateGraphQLTypeCalled = false
5151
override fun willGenerateGraphQLType(type: KType): GraphQLType? {
5252
willGenerateGraphQLTypeCalled = true
@@ -67,7 +67,7 @@ class SchemaGeneratorHooksTest {
6767

6868
@Test
6969
fun `calls hook to filter property`() {
70-
class MockSchemaGeneratorHooks : NoopSchemaGeneratorHooks() {
70+
class MockSchemaGeneratorHooks : SchemaGeneratorHooks {
7171
var calledFilterFunction = false
7272

7373
override fun isValidProperty(property: KProperty<*>): Boolean {
@@ -88,7 +88,7 @@ class SchemaGeneratorHooksTest {
8888

8989
@Test
9090
fun `calls hook to filter functions`() {
91-
class MockSchemaGeneratorHooks : NoopSchemaGeneratorHooks() {
91+
class MockSchemaGeneratorHooks : SchemaGeneratorHooks {
9292
var calledFilterFunction = false
9393

9494
override fun isValidFunction(function: KFunction<*>): Boolean {
@@ -108,7 +108,7 @@ class SchemaGeneratorHooksTest {
108108

109109
@Test
110110
fun `calls hook after generating object type`() {
111-
class MockSchemaGeneratorHooks : NoopSchemaGeneratorHooks() {
111+
class MockSchemaGeneratorHooks : SchemaGeneratorHooks {
112112
var lastSeenType: KType? = null
113113
var lastSeenGeneratedType: GraphQLType? = null
114114
override fun didGenerateGraphQLType(type: KType, generatedType: GraphQLType) {
@@ -128,7 +128,7 @@ class SchemaGeneratorHooksTest {
128128

129129
@Test
130130
fun `calls hook before adding data fetcher`() {
131-
class MockSchemaGeneratorHooks : NoopSchemaGeneratorHooks() {
131+
class MockSchemaGeneratorHooks : SchemaGeneratorHooks {
132132
var didGenerateDataFetcherCalled = false
133133
var lastSeenFunction: KFunction<*>? = null
134134
var lastReturnedDataFetcher: WrappingDataFetcher? = null
@@ -156,7 +156,7 @@ class SchemaGeneratorHooksTest {
156156

157157
@Test
158158
fun `calls hook before adding query to schema`() {
159-
class MockSchemaGeneratorHooks : NoopSchemaGeneratorHooks() {
159+
class MockSchemaGeneratorHooks : SchemaGeneratorHooks {
160160
override fun didGenerateQueryType(
161161
function: KFunction<*>,
162162
fieldDefinition: GraphQLFieldDefinition
@@ -182,7 +182,7 @@ class SchemaGeneratorHooksTest {
182182

183183
@Test
184184
fun `calls hook before adding mutation to schema`() {
185-
class MockSchemaGeneratorHooks : NoopSchemaGeneratorHooks() {
185+
class MockSchemaGeneratorHooks : SchemaGeneratorHooks {
186186
override fun didGenerateMutationType(
187187
function: KFunction<*>,
188188
fieldDefinition: GraphQLFieldDefinition

0 commit comments

Comments
 (0)