diff --git a/pom.xml b/pom.xml
index 56dcae9b..6e62adee 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
com.graphql-java-kickstart
graphql-java-tools
- 6.0.3-SNAPSHOT
+ 6.1.0-SNAPSHOT
jar
GraphQL Java Tools
diff --git a/src/main/kotlin/graphql/kickstart/tools/SchemaObjects.kt b/src/main/kotlin/graphql/kickstart/tools/SchemaObjects.kt
index 89bdd4b5..c29a46b4 100644
--- a/src/main/kotlin/graphql/kickstart/tools/SchemaObjects.kt
+++ b/src/main/kotlin/graphql/kickstart/tools/SchemaObjects.kt
@@ -4,7 +4,6 @@ import graphql.schema.GraphQLCodeRegistry
import graphql.schema.GraphQLObjectType
import graphql.schema.GraphQLSchema
import graphql.schema.GraphQLType
-import graphql.schema.visibility.NoIntrospectionGraphqlFieldVisibility
/**
* @author Andrew Potter
@@ -14,11 +13,7 @@ data class SchemaObjects(val query: GraphQLObjectType, val mutation: GraphQLObje
/**
* Makes a GraphQLSchema with query, mutation and subscription.
*/
- fun toSchema(introspectionEnabled: Boolean): GraphQLSchema {
- if (!introspectionEnabled) {
- codeRegistryBuilder.fieldVisibility(NoIntrospectionGraphqlFieldVisibility.NO_INTROSPECTION_FIELD_VISIBILITY)
- }
-
+ fun toSchema(): GraphQLSchema {
return GraphQLSchema.newSchema()
.query(query)
.mutation(mutation)
diff --git a/src/main/kotlin/graphql/kickstart/tools/SchemaParser.kt b/src/main/kotlin/graphql/kickstart/tools/SchemaParser.kt
index 8dba70ce..50f6360e 100644
--- a/src/main/kotlin/graphql/kickstart/tools/SchemaParser.kt
+++ b/src/main/kotlin/graphql/kickstart/tools/SchemaParser.kt
@@ -6,6 +6,7 @@ import graphql.schema.*
import graphql.schema.idl.RuntimeWiring
import graphql.schema.idl.ScalarInfo
import graphql.schema.idl.SchemaGeneratorHelper
+import graphql.schema.visibility.NoIntrospectionGraphqlFieldVisibility
import org.slf4j.LoggerFactory
import java.util.*
import kotlin.reflect.KClass
@@ -62,9 +63,13 @@ class SchemaParser internal constructor(scanResult: ScannedSchemaObjects, privat
* Parses the given schema with respect to the given dictionary and returns GraphQL objects.
*/
fun parseSchemaObjects(): SchemaObjects {
+ if (!options.introspectionEnabled) {
+ codeRegistryBuilder.fieldVisibility(NoIntrospectionGraphqlFieldVisibility.NO_INTROSPECTION_FIELD_VISIBILITY)
+ }
+ // this overrides the above introspection enabled setting obviously... todo: add documentation
+ options.fieldVisilibity?.let { codeRegistryBuilder.fieldVisibility(it) }
// Create GraphQL objects
-// val inputObjects = inputObjectDefinitions.map { createInputObject(it, listOf())}
val inputObjects: MutableList = mutableListOf()
inputObjectDefinitions.forEach {
if (inputObjects.none { io -> io.name == it.name }) {
@@ -101,7 +106,7 @@ class SchemaParser internal constructor(scanResult: ScannedSchemaObjects, privat
/**
* Parses the given schema with respect to the given dictionary and returns a GraphQLSchema
*/
- fun makeExecutableSchema(): GraphQLSchema = parseSchemaObjects().toSchema(options.introspectionEnabled)
+ fun makeExecutableSchema(): GraphQLSchema = parseSchemaObjects().toSchema()
/**
* Returns any unused type definitions that were found in the schema
diff --git a/src/main/kotlin/graphql/kickstart/tools/SchemaParserBuilder.kt b/src/main/kotlin/graphql/kickstart/tools/SchemaParserBuilder.kt
index f8e2b2bd..0b725aa9 100644
--- a/src/main/kotlin/graphql/kickstart/tools/SchemaParserBuilder.kt
+++ b/src/main/kotlin/graphql/kickstart/tools/SchemaParserBuilder.kt
@@ -10,6 +10,7 @@ import graphql.schema.DataFetchingEnvironment
import graphql.schema.GraphQLScalarType
import graphql.schema.idl.RuntimeWiring
import graphql.schema.idl.SchemaDirectiveWiring
+import graphql.schema.visibility.GraphqlFieldVisibility
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.ReceiveChannel
@@ -28,458 +29,465 @@ import kotlin.reflect.KClass
*/
class SchemaParserBuilder constructor(private val dictionary: SchemaParserDictionary = SchemaParserDictionary()) {
- private val schemaString = StringBuilder()
- private val files = mutableListOf()
- private val resolvers = mutableListOf>()
- private val scalars = mutableListOf()
- private val runtimeWiringBuilder = RuntimeWiring.newRuntimeWiring()
- private var options = SchemaParserOptions.defaultOptions()
-
- /**
- * Add GraphQL schema files from the classpath.
- */
- fun files(vararg files: String) = this.apply {
- files.forEach { this.file(it) }
- }
-
- /**
- * Add a GraphQL Schema file from the classpath.
- */
- fun file(filename: String) = this.apply {
- files.add(filename)
- }
+ private val schemaString = StringBuilder()
+ private val files = mutableListOf()
+ private val resolvers = mutableListOf>()
+ private val scalars = mutableListOf()
+ private val runtimeWiringBuilder = RuntimeWiring.newRuntimeWiring()
+ private var options = SchemaParserOptions.defaultOptions()
+
+ /**
+ * Add GraphQL schema files from the classpath.
+ */
+ fun files(vararg files: String) = this.apply {
+ files.forEach { this.file(it) }
+ }
+
+ /**
+ * Add a GraphQL Schema file from the classpath.
+ */
+ fun file(filename: String) = this.apply {
+ files.add(filename)
+ }
+
+ /**
+ * Add a GraphQL schema string directly.
+ */
+ fun schemaString(string: String) = this.apply {
+ if (schemaString.isNotEmpty()) {
+ schemaString.append("\n")
+ }
+ schemaString.append(string)
+ }
+
+ /**
+ * Add GraphQLResolvers to the parser's dictionary.
+ */
+ fun resolvers(vararg resolvers: GraphQLResolver<*>) = this.apply {
+ this.resolvers.addAll(resolvers)
+ }
+
+ /**
+ * Add GraphQLResolvers to the parser's dictionary.
+ */
+ fun resolvers(resolvers: List>) = this.apply {
+ this.resolvers.addAll(resolvers)
+ }
+
+ /**
+ * Add scalars to the parser's dictionary.
+ */
+ fun scalars(vararg scalars: GraphQLScalarType) = this.apply {
+ this.scalars.addAll(scalars)
+ }
+
+ /**
+ * Add scalars to the parser's dictionary.
+ */
+ fun scalars(scalars: List) = this.apply {
+ this.scalars.addAll(scalars)
+ }
+
+ fun directive(name: String, directive: SchemaDirectiveWiring) = this.apply {
+ this.runtimeWiringBuilder.directive(name, directive)
+ }
+
+ fun directiveWiring(directive: SchemaDirectiveWiring) = this.apply {
+ this.runtimeWiringBuilder.directiveWiring(directive)
+ }
+
+ /**
+ * Add arbitrary classes to the parser's dictionary, overriding the generated type name.
+ */
+ fun dictionary(name: String, clazz: Class<*>) = this.apply {
+ this.dictionary.add(name, clazz)
+ }
+
+ /**
+ * Add arbitrary classes to the parser's dictionary, overriding the generated type name.
+ */
+ fun dictionary(name: String, clazz: KClass<*>) = this.apply {
+ this.dictionary.add(name, clazz)
+ }
+
+ /**
+ * Add arbitrary classes to the parser's dictionary, overriding the generated type name.
+ */
+ fun dictionary(dictionary: Map>) = this.apply {
+ this.dictionary.add(dictionary)
+ }
+
+ /**
+ * Add arbitrary classes to the parser's dictionary.
+ */
+ fun dictionary(clazz: Class<*>) = this.apply {
+ this.dictionary.add(clazz)
+ }
+
+ /**
+ * Add arbitrary classes to the parser's dictionary.
+ */
+ fun dictionary(clazz: KClass<*>) = this.apply {
+ this.dictionary.add(clazz)
+ }
+
+ /**
+ * Add arbitrary classes to the parser's dictionary.
+ */
+ fun dictionary(vararg dictionary: Class<*>) = this.apply {
+ this.dictionary.add(*dictionary)
+ }
+
+ /**
+ * Add arbitrary classes to the parser's dictionary.
+ */
+ fun dictionary(vararg dictionary: KClass<*>) = this.apply {
+ this.dictionary.add(*dictionary)
+ }
+
+ /**
+ * Add arbitrary classes to the parser's dictionary.
+ */
+ fun dictionary(dictionary: Collection>) = this.apply {
+ this.dictionary.add(dictionary)
+ }
+
+ fun options(options: SchemaParserOptions) = this.apply {
+ this.options = options
+ }
+
+ /**
+ * Scan for classes with the supplied schema and dictionary. Used for testing.
+ */
+ private fun scan(): ScannedSchemaObjects {
+ val definitions = appendDynamicDefinitions(parseDefinitions())
+ val customScalars = scalars.associateBy { it.name }
+
+ return SchemaClassScanner(dictionary.getDictionary(), definitions, resolvers, customScalars, options)
+ .scanForClasses()
+ }
+
+ private fun parseDefinitions() = parseDocuments().flatMap { it.definitions }
+
+ private fun appendDynamicDefinitions(baseDefinitions: List>): List> {
+ val definitions = baseDefinitions.toMutableList()
+ options.typeDefinitionFactories.forEach { definitions.addAll(it.create(definitions)) }
+ return definitions.toList()
+ }
+
+ private fun parseDocuments(): List {
+ val parser = Parser()
+ val documents = mutableListOf()
+ try {
+ files.forEach { documents.add(parser.parseDocument(readFile(it), it)) }
+
+ if (schemaString.isNotEmpty()) {
+ documents.add(parser.parseDocument(this.schemaString.toString()))
+ }
+ } catch (pce: ParseCancellationException) {
+ val cause = pce.cause
+ if (cause != null && cause is RecognitionException) {
+ throw InvalidSchemaError(pce, cause)
+ } else {
+ throw pce
+ }
+ }
+ return documents
+ }
+
+ private fun readFile(filename: String): String {
+ return java.io.BufferedReader(java.io.InputStreamReader(
+ object : Any() {}.javaClass.classLoader.getResourceAsStream(filename)
+ ?: throw java.io.FileNotFoundException("classpath:$filename")
+ )).readText()
+ }
+
+ /**
+ * Build the parser with the supplied schema and dictionary.
+ */
+ fun build() = SchemaParser(scan(), options, runtimeWiringBuilder.build())
+}
- /**
- * Add a GraphQL schema string directly.
- */
- fun schemaString(string: String) = this.apply {
- if (schemaString.isNotEmpty()) {
- schemaString.append("\n")
- }
- schemaString.append(string)
- }
+class InvalidSchemaError(pce: ParseCancellationException, private val recognitionException: RecognitionException) : RuntimeException(pce) {
+ override val message: String?
+ get() = "Invalid schema provided (${recognitionException.javaClass.name}) at: ${recognitionException.offendingToken}"
+}
- /**
- * Add GraphQLResolvers to the parser's dictionary.
- */
- fun resolvers(vararg resolvers: GraphQLResolver<*>) = this.apply {
- this.resolvers.addAll(resolvers)
- }
+class SchemaParserDictionary {
- /**
- * Add GraphQLResolvers to the parser's dictionary.
- */
- fun resolvers(resolvers: List>) = this.apply {
- this.resolvers.addAll(resolvers)
- }
+ private val dictionary: BiMap> = BiMap.create()
+
+ fun getDictionary(): BiMap> = BiMap.unmodifiableBiMap(dictionary)
+
+ /**
+ * Add arbitrary classes to the parser's dictionary, overriding the generated type name.
+ */
+ fun add(name: String, clazz: Class<*>) = this.apply {
+ this.dictionary.put(name, clazz)
+ }
+
+ /**
+ * Add arbitrary classes to the parser's dictionary, overriding the generated type name.
+ */
+ fun add(name: String, clazz: KClass<*>) = this.apply {
+ this.dictionary.put(name, clazz.java)
+ }
+
+ /**
+ * Add arbitrary classes to the parser's dictionary, overriding the generated type name.
+ */
+ fun add(dictionary: Map>) = this.apply {
+ this.dictionary.putAll(dictionary)
+ }
+
+ /**
+ * Add arbitrary classes to the parser's dictionary.
+ */
+ fun add(clazz: Class<*>) = this.apply {
+ this.add(clazz.simpleName, clazz)
+ }
+
+ /**
+ * Add arbitrary classes to the parser's dictionary.
+ */
+ fun add(clazz: KClass<*>) = this.apply {
+ this.add(clazz.java.simpleName, clazz)
+ }
+
+ /**
+ * Add arbitrary classes to the parser's dictionary.
+ */
+ fun add(vararg dictionary: Class<*>) = this.apply {
+ dictionary.forEach { this.add(it) }
+ }
+
+ /**
+ * Add arbitrary classes to the parser's dictionary.
+ */
+ fun add(vararg dictionary: KClass<*>) = this.apply {
+ dictionary.forEach { this.add(it) }
+ }
+
+ /**
+ * Add arbitrary classes to the parser's dictionary.
+ */
+ fun add(dictionary: Collection>) = this.apply {
+ dictionary.forEach { this.add(it) }
+ }
+}
- /**
- * Add scalars to the parser's dictionary.
- */
- fun scalars(vararg scalars: GraphQLScalarType) = this.apply {
- this.scalars.addAll(scalars)
- }
+data class SchemaParserOptions internal constructor(
+ val contextClass: Class<*>?,
+ val genericWrappers: List,
+ val allowUnimplementedResolvers: Boolean,
+ val objectMapperProvider: PerFieldObjectMapperProvider,
+ val proxyHandlers: List,
+ val preferGraphQLResolver: Boolean,
+ val introspectionEnabled: Boolean,
+ val coroutineContextProvider: CoroutineContextProvider,
+ val typeDefinitionFactories: List,
+ val fieldVisilibity: GraphqlFieldVisibility?
+) {
+ companion object {
+ @JvmStatic
+ fun newOptions() = Builder()
- /**
- * Add scalars to the parser's dictionary.
- */
- fun scalars(scalars: List) = this.apply {
- this.scalars.addAll(scalars)
- }
+ @JvmStatic
+ @ExperimentalCoroutinesApi
+ fun defaultOptions() = Builder().build()
+ }
- fun directive(name: String, directive: SchemaDirectiveWiring) = this.apply {
- this.runtimeWiringBuilder.directive(name, directive)
- }
+ val coroutineContext: CoroutineContext
+ get() = coroutineContextProvider.provide()
- fun directiveWiring(directive: SchemaDirectiveWiring) = this.apply {
- this.runtimeWiringBuilder.directiveWiring(directive)
- }
+ class Builder {
+ private var contextClass: Class<*>? = null
+ private val genericWrappers: MutableList = mutableListOf()
+ private var useDefaultGenericWrappers = true
+ private var allowUnimplementedResolvers = false
+ private var objectMapperProvider: PerFieldObjectMapperProvider = PerFieldConfiguringObjectMapperProvider()
+ private val proxyHandlers: MutableList = mutableListOf(Spring4AopProxyHandler(), GuiceAopProxyHandler(), JavassistProxyHandler(), WeldProxyHandler())
+ private var preferGraphQLResolver = false
+ private var introspectionEnabled = true
+ private var coroutineContextProvider: CoroutineContextProvider? = null
+ private var typeDefinitionFactories: MutableList = mutableListOf(RelayConnectionFactory())
+ private var fieldVisibility: GraphqlFieldVisibility? = null
- /**
- * Add arbitrary classes to the parser's dictionary, overriding the generated type name.
- */
- fun dictionary(name: String, clazz: Class<*>) = this.apply {
- this.dictionary.add(name, clazz)
+ fun contextClass(contextClass: Class<*>) = this.apply {
+ this.contextClass = contextClass
}
- /**
- * Add arbitrary classes to the parser's dictionary, overriding the generated type name.
- */
- fun dictionary(name: String, clazz: KClass<*>) = this.apply {
- this.dictionary.add(name, clazz)
+ fun contextClass(contextClass: KClass<*>) = this.apply {
+ this.contextClass = contextClass.java
}
- /**
- * Add arbitrary classes to the parser's dictionary, overriding the generated type name.
- */
- fun dictionary(dictionary: Map>) = this.apply {
- this.dictionary.add(dictionary)
+ fun genericWrappers(genericWrappers: List) = this.apply {
+ this.genericWrappers.addAll(genericWrappers)
}
- /**
- * Add arbitrary classes to the parser's dictionary.
- */
- fun dictionary(clazz: Class<*>) = this.apply {
- this.dictionary.add(clazz)
+ fun genericWrappers(vararg genericWrappers: GenericWrapper) = this.apply {
+ this.genericWrappers.addAll(genericWrappers)
}
- /**
- * Add arbitrary classes to the parser's dictionary.
- */
- fun dictionary(clazz: KClass<*>) = this.apply {
- this.dictionary.add(clazz)
+ fun useDefaultGenericWrappers(useDefaultGenericWrappers: Boolean) = this.apply {
+ this.useDefaultGenericWrappers = useDefaultGenericWrappers
}
- /**
- * Add arbitrary classes to the parser's dictionary.
- */
- fun dictionary(vararg dictionary: Class<*>) = this.apply {
- this.dictionary.add(*dictionary)
+ fun allowUnimplementedResolvers(allowUnimplementedResolvers: Boolean) = this.apply {
+ this.allowUnimplementedResolvers = allowUnimplementedResolvers
}
- /**
- * Add arbitrary classes to the parser's dictionary.
- */
- fun dictionary(vararg dictionary: KClass<*>) = this.apply {
- this.dictionary.add(*dictionary)
+ fun preferGraphQLResolver(preferGraphQLResolver: Boolean) = this.apply {
+ this.preferGraphQLResolver = preferGraphQLResolver
}
- /**
- * Add arbitrary classes to the parser's dictionary.
- */
- fun dictionary(dictionary: Collection>) = this.apply {
- this.dictionary.add(dictionary)
+ fun objectMapperConfigurer(objectMapperConfigurer: ObjectMapperConfigurer) = this.apply {
+ this.objectMapperProvider = PerFieldConfiguringObjectMapperProvider(objectMapperConfigurer)
}
- fun options(options: SchemaParserOptions) = this.apply {
- this.options = options
+ fun objectMapperProvider(objectMapperProvider: PerFieldObjectMapperProvider) = this.apply {
+ this.objectMapperProvider = objectMapperProvider
}
- /**
- * Scan for classes with the supplied schema and dictionary. Used for testing.
- */
- private fun scan(): ScannedSchemaObjects {
- val definitions = appendDynamicDefinitions(parseDefinitions())
- val customScalars = scalars.associateBy { it.name }
-
- return SchemaClassScanner(dictionary.getDictionary(), definitions, resolvers, customScalars, options)
- .scanForClasses()
+ fun objectMapperConfigurer(objectMapperConfigurer: (ObjectMapper, ObjectMapperConfigurerContext) -> Unit) = this.apply {
+ this.objectMapperConfigurer(ObjectMapperConfigurer(objectMapperConfigurer))
}
- private fun parseDefinitions() = parseDocuments().flatMap { it.definitions }
-
- private fun appendDynamicDefinitions(baseDefinitions: List>): List> {
- val definitions = baseDefinitions.toMutableList()
- options.typeDefinitionFactories.forEach { definitions.addAll(it.create(definitions)) }
- return definitions.toList()
+ fun addProxyHandler(proxyHandler: ProxyHandler) = this.apply {
+ this.proxyHandlers.add(proxyHandler)
}
- private fun parseDocuments(): List {
- val parser = Parser()
- val documents = mutableListOf()
- try {
- files.forEach { documents.add(parser.parseDocument(readFile(it), it)) }
-
- if (schemaString.isNotEmpty()) {
- documents.add(parser.parseDocument(this.schemaString.toString()))
- }
- } catch (pce: ParseCancellationException) {
- val cause = pce.cause
- if (cause != null && cause is RecognitionException) {
- throw InvalidSchemaError(pce, cause)
- } else {
- throw pce
- }
- }
- return documents
+ fun introspectionEnabled(introspectionEnabled: Boolean) = this.apply {
+ this.introspectionEnabled = introspectionEnabled
}
- private fun readFile(filename: String): String {
- return java.io.BufferedReader(java.io.InputStreamReader(
- object : Any() {}.javaClass.classLoader.getResourceAsStream(filename)
- ?: throw java.io.FileNotFoundException("classpath:$filename")
- )).readText()
+ fun coroutineContext(context: CoroutineContext) = this.apply {
+ this.coroutineContextProvider = DefaultCoroutineContextProvider(context)
}
- /**
- * Build the parser with the supplied schema and dictionary.
- */
- fun build() = SchemaParser(scan(), options, runtimeWiringBuilder.build())
-}
-
-class InvalidSchemaError(pce: ParseCancellationException, private val recognitionException: RecognitionException) : RuntimeException(pce) {
- override val message: String?
- get() = "Invalid schema provided (${recognitionException.javaClass.name}) at: ${recognitionException.offendingToken}"
-}
-
-class SchemaParserDictionary {
-
- private val dictionary: BiMap> = BiMap.create()
-
- fun getDictionary(): BiMap> = BiMap.unmodifiableBiMap(dictionary)
-
- /**
- * Add arbitrary classes to the parser's dictionary, overriding the generated type name.
- */
- fun add(name: String, clazz: Class<*>) = this.apply {
- this.dictionary.put(name, clazz)
+ fun coroutineContextProvider(contextProvider: CoroutineContextProvider) = this.apply {
+ this.coroutineContextProvider = contextProvider
}
- /**
- * Add arbitrary classes to the parser's dictionary, overriding the generated type name.
- */
- fun add(name: String, clazz: KClass<*>) = this.apply {
- this.dictionary.put(name, clazz.java)
+ fun typeDefinitionFactory(factory: TypeDefinitionFactory) = this.apply {
+ this.typeDefinitionFactories.add(factory)
}
- /**
- * Add arbitrary classes to the parser's dictionary, overriding the generated type name.
- */
- fun add(dictionary: Map>) = this.apply {
- this.dictionary.putAll(dictionary)
+ fun fieldVisibility(fieldVisilibity: GraphqlFieldVisibility) = this.apply {
+ this.fieldVisibility = fieldVisibility
}
- /**
- * Add arbitrary classes to the parser's dictionary.
- */
- fun add(clazz: Class<*>) = this.apply {
- this.add(clazz.simpleName, clazz)
- }
+ @ExperimentalCoroutinesApi
+ fun build(): SchemaParserOptions {
+ val coroutineContextProvider = coroutineContextProvider ?: DefaultCoroutineContextProvider(Dispatchers.Default)
+ val wrappers = if (useDefaultGenericWrappers) {
+ genericWrappers + listOf(
+ GenericWrapper(Future::class, 0),
+ GenericWrapper(CompletableFuture::class, 0),
+ GenericWrapper(CompletionStage::class, 0),
+ GenericWrapper(Publisher::class, 0),
+ GenericWrapper.withTransformer(ReceiveChannel::class, 0, { receiveChannel, environment ->
+ environment.coroutineScope().publish(coroutineContextProvider.provide()) {
+ try {
+ for (item in receiveChannel) {
+ send(item)
+ }
+ } finally {
+ receiveChannel.cancel()
+ }
+ }
+ })
+ )
+ } else {
+ genericWrappers
+ }
- /**
- * Add arbitrary classes to the parser's dictionary.
- */
- fun add(clazz: KClass<*>) = this.apply {
- this.add(clazz.java.simpleName, clazz)
+ return SchemaParserOptions(contextClass, wrappers, allowUnimplementedResolvers, objectMapperProvider,
+ proxyHandlers, preferGraphQLResolver, introspectionEnabled, coroutineContextProvider,
+ typeDefinitionFactories, fieldVisibility
+ )
}
+ }
- /**
- * Add arbitrary classes to the parser's dictionary.
- */
- fun add(vararg dictionary: Class<*>) = this.apply {
- dictionary.forEach { this.add(it) }
+ internal class DefaultCoroutineContextProvider(val coroutineContext: CoroutineContext) : CoroutineContextProvider {
+ override fun provide(): CoroutineContext {
+ return coroutineContext
}
+ }
- /**
- * Add arbitrary classes to the parser's dictionary.
- */
- fun add(vararg dictionary: KClass<*>) = this.apply {
- dictionary.forEach { this.add(it) }
- }
+ data class GenericWrapper(
+ val type: Class<*>,
+ val index: Int,
+ val transformer: (Any, DataFetchingEnvironment) -> Any? = { x, _ -> x },
+ val schemaWrapper: (JavaType) -> JavaType = { x -> x }
+ ) {
- /**
- * Add arbitrary classes to the parser's dictionary.
- */
- fun add(dictionary: Collection>) = this.apply {
- dictionary.forEach { this.add(it) }
- }
-}
+ constructor(type: Class<*>, index: Int) : this(type, index, { x, _ -> x })
+ constructor(type: KClass<*>, index: Int) : this(type.java, index, { x, _ -> x })
-data class SchemaParserOptions internal constructor(
- val contextClass: Class<*>?,
- val genericWrappers: List,
- val allowUnimplementedResolvers: Boolean,
- val objectMapperProvider: PerFieldObjectMapperProvider,
- val proxyHandlers: List,
- val preferGraphQLResolver: Boolean,
- val introspectionEnabled: Boolean,
- val coroutineContextProvider: CoroutineContextProvider,
- val typeDefinitionFactories: List
-) {
companion object {
- @JvmStatic
- fun newOptions() = Builder()
-
- @JvmStatic
- @ExperimentalCoroutinesApi
- fun defaultOptions() = Builder().build()
- }
-
- val coroutineContext: CoroutineContext
- get() = coroutineContextProvider.provide()
-
- class Builder {
- private var contextClass: Class<*>? = null
- private val genericWrappers: MutableList = mutableListOf()
- private var useDefaultGenericWrappers = true
- private var allowUnimplementedResolvers = false
- private var objectMapperProvider: PerFieldObjectMapperProvider = PerFieldConfiguringObjectMapperProvider()
- private val proxyHandlers: MutableList = mutableListOf(Spring4AopProxyHandler(), GuiceAopProxyHandler(), JavassistProxyHandler(), WeldProxyHandler())
- private var preferGraphQLResolver = false
- private var introspectionEnabled = true
- private var coroutineContextProvider: CoroutineContextProvider? = null
- private var coroutineContext: CoroutineContext? = null
- private var typeDefinitionFactories: MutableList = mutableListOf(RelayConnectionFactory())
-
- fun contextClass(contextClass: Class<*>) = this.apply {
- this.contextClass = contextClass
- }
-
- fun contextClass(contextClass: KClass<*>) = this.apply {
- this.contextClass = contextClass.java
- }
-
- fun genericWrappers(genericWrappers: List) = this.apply {
- this.genericWrappers.addAll(genericWrappers)
- }
-
- fun genericWrappers(vararg genericWrappers: GenericWrapper) = this.apply {
- this.genericWrappers.addAll(genericWrappers)
- }
-
- fun useDefaultGenericWrappers(useDefaultGenericWrappers: Boolean) = this.apply {
- this.useDefaultGenericWrappers = useDefaultGenericWrappers
- }
-
- fun allowUnimplementedResolvers(allowUnimplementedResolvers: Boolean) = this.apply {
- this.allowUnimplementedResolvers = allowUnimplementedResolvers
- }
-
- fun preferGraphQLResolver(preferGraphQLResolver: Boolean) = this.apply {
- this.preferGraphQLResolver = preferGraphQLResolver
- }
-
- fun objectMapperConfigurer(objectMapperConfigurer: ObjectMapperConfigurer) = this.apply {
- this.objectMapperProvider = PerFieldConfiguringObjectMapperProvider(objectMapperConfigurer)
- }
-
- fun objectMapperProvider(objectMapperProvider: PerFieldObjectMapperProvider) = this.apply {
- this.objectMapperProvider = objectMapperProvider
- }
-
- fun objectMapperConfigurer(objectMapperConfigurer: (ObjectMapper, ObjectMapperConfigurerContext) -> Unit) = this.apply {
- this.objectMapperConfigurer(ObjectMapperConfigurer(objectMapperConfigurer))
- }
-
- fun addProxyHandler(proxyHandler: ProxyHandler) = this.apply {
- this.proxyHandlers.add(proxyHandler)
- }
-
- fun introspectionEnabled(introspectionEnabled: Boolean) = this.apply {
- this.introspectionEnabled = introspectionEnabled
- }
-
- fun coroutineContext(context: CoroutineContext) = this.apply {
- this.coroutineContextProvider = DefaultCoroutineContextProvider(context)
- }
-
- fun coroutineContextProvider(contextProvider: CoroutineContextProvider) = this.apply {
- this.coroutineContextProvider = contextProvider
- }
-
- fun typeDefinitionFactory(factory: TypeDefinitionFactory) = this.apply {
- this.typeDefinitionFactories.add(factory)
- }
-
- @ExperimentalCoroutinesApi
- fun build(): SchemaParserOptions {
- val coroutineContextProvider = coroutineContextProvider ?: DefaultCoroutineContextProvider(Dispatchers.Default)
- val wrappers = if (useDefaultGenericWrappers) {
- genericWrappers + listOf(
- GenericWrapper(Future::class, 0),
- GenericWrapper(CompletableFuture::class, 0),
- GenericWrapper(CompletionStage::class, 0),
- GenericWrapper(Publisher::class, 0),
- GenericWrapper.withTransformer(ReceiveChannel::class, 0, { receiveChannel, environment ->
- environment.coroutineScope().publish(coroutineContextProvider.provide()) {
- try {
- for (item in receiveChannel) {
- send(item)
- }
- } finally {
- receiveChannel.cancel()
- }
- }
- })
- )
- } else {
- genericWrappers
- }
-
- return SchemaParserOptions(contextClass, wrappers, allowUnimplementedResolvers, objectMapperProvider,
- proxyHandlers, preferGraphQLResolver, introspectionEnabled, coroutineContextProvider, typeDefinitionFactories)
- }
- }
- internal class DefaultCoroutineContextProvider(val coroutineContext: CoroutineContext): CoroutineContextProvider {
- override fun provide(): CoroutineContext {
- return coroutineContext
- }
- }
-
- data class GenericWrapper(
- val type: Class<*>,
- val index: Int,
- val transformer: (Any, DataFetchingEnvironment) -> Any? = { x, _ -> x },
- val schemaWrapper: (JavaType) -> JavaType = { x -> x }
- ) {
-
- constructor(type: Class<*>, index: Int) : this(type, index, { x, _ -> x })
- constructor(type: KClass<*>, index: Int) : this(type.java, index, { x, _ -> x })
-
- companion object {
-
- @Suppress("UNCHECKED_CAST")
- @JvmStatic
- fun withTransformer(
- type: Class,
- index: Int,
- transformer: (T, DataFetchingEnvironment) -> Any?,
- schemaWrapper: (JavaType) -> JavaType = { x -> x }
- ): GenericWrapper where T : Any {
- return GenericWrapper(type, index, transformer as (Any, DataFetchingEnvironment) -> Any?, schemaWrapper)
- }
-
- fun withTransformer(
- type: KClass,
- index: Int,
- transformer: (T, DataFetchingEnvironment) -> Any?,
- schemaWrapper: (JavaType) -> JavaType = { x -> x }
- ): GenericWrapper where T : Any {
- return withTransformer(type.java, index, transformer, schemaWrapper)
- }
-
- @JvmStatic
- fun withTransformer(
- type: Class,
- index: Int,
- transformer: (T) -> Any?,
- schemaWrapper: (JavaType) -> JavaType = { x -> x }
- ): GenericWrapper where T : Any {
- return withTransformer(type, index, { x, _ -> transformer.invoke(x) }, schemaWrapper)
- }
-
- fun withTransformer(
- type: KClass,
- index: Int,
- transformer: (T) -> Any?,
- schemaWrapper: (JavaType) -> JavaType = { x -> x }
- ): GenericWrapper where T : Any {
- return withTransformer(type.java, index, transformer, schemaWrapper)
- }
-
- @JvmStatic
- fun listCollectionWithTransformer(
- type: Class,
- index: Int,
- transformer: (T) -> Any?
- ): GenericWrapper where T : Any {
- return withTransformer(
- type,
- index,
- transformer,
- { innerType -> ParameterizedTypeImpl.make(List::class.java, arrayOf(innerType), null) }
- )
- }
-
- fun listCollectionWithTransformer(
- type: KClass,
- index: Int,
- transformer: (T) -> Any?
- ): GenericWrapper where T : Any {
- return listCollectionWithTransformer(type.java, index, transformer)
- }
- }
-
- }
+ @Suppress("UNCHECKED_CAST")
+ @JvmStatic
+ fun withTransformer(
+ type: Class,
+ index: Int,
+ transformer: (T, DataFetchingEnvironment) -> Any?,
+ schemaWrapper: (JavaType) -> JavaType = { x -> x }
+ ): GenericWrapper where T : Any {
+ return GenericWrapper(type, index, transformer as (Any, DataFetchingEnvironment) -> Any?, schemaWrapper)
+ }
+
+ fun withTransformer(
+ type: KClass,
+ index: Int,
+ transformer: (T, DataFetchingEnvironment) -> Any?,
+ schemaWrapper: (JavaType) -> JavaType = { x -> x }
+ ): GenericWrapper where T : Any {
+ return withTransformer(type.java, index, transformer, schemaWrapper)
+ }
+
+ @JvmStatic
+ fun withTransformer(
+ type: Class,
+ index: Int,
+ transformer: (T) -> Any?,
+ schemaWrapper: (JavaType) -> JavaType = { x -> x }
+ ): GenericWrapper where T : Any {
+ return withTransformer(type, index, { x, _ -> transformer.invoke(x) }, schemaWrapper)
+ }
+
+ fun withTransformer(
+ type: KClass,
+ index: Int,
+ transformer: (T) -> Any?,
+ schemaWrapper: (JavaType) -> JavaType = { x -> x }
+ ): GenericWrapper where T : Any {
+ return withTransformer(type.java, index, transformer, schemaWrapper)
+ }
+
+ @JvmStatic
+ fun listCollectionWithTransformer(
+ type: Class,
+ index: Int,
+ transformer: (T) -> Any?
+ ): GenericWrapper where T : Any {
+ return withTransformer(
+ type,
+ index,
+ transformer,
+ { innerType -> ParameterizedTypeImpl.make(List::class.java, arrayOf(innerType), null) }
+ )
+ }
+
+ fun listCollectionWithTransformer(
+ type: KClass,
+ index: Int,
+ transformer: (T) -> Any?
+ ): GenericWrapper where T : Any {
+ return listCollectionWithTransformer(type.java, index, transformer)
+ }
+ }
+
+ }
}