@@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.ObjectMapper
44import com.google.common.collect.BiMap
55import com.google.common.collect.HashBiMap
66import com.google.common.collect.Maps
7+ import graphql.language.Document
78import graphql.parser.Parser
89import graphql.schema.DataFetchingEnvironment
910import graphql.schema.GraphQLScalarType
@@ -22,6 +23,7 @@ import kotlin.reflect.KClass
2223class SchemaParserBuilder constructor(private val dictionary : SchemaParserDictionary = SchemaParserDictionary ()) {
2324
2425 private val schemaString = StringBuilder ()
26+ private val files = mutableListOf<String >()
2527 private val resolvers = mutableListOf<GraphQLResolver <* >>()
2628 private val scalars = mutableListOf<GraphQLScalarType >()
2729 private var options = SchemaParserOptions .defaultOptions()
@@ -37,16 +39,17 @@ class SchemaParserBuilder constructor(private val dictionary: SchemaParserDictio
3739 * Add a GraphQL Schema file from the classpath.
3840 */
3941 fun file (filename : String ) = this .apply {
40- this .schemaString(java.io.BufferedReader (java.io.InputStreamReader (
41- object : Any () {}.javaClass.classLoader.getResourceAsStream(filename) ? : throw java.io.FileNotFoundException (" classpath:$filename " )
42- )).readText())
42+ files.add(filename)
4343 }
4444
4545 /* *
4646 * Add a GraphQL schema string directly.
4747 */
4848 fun schemaString (string : String ) = this .apply {
49- schemaString.append(" \n " ).append(string)
49+ if (! schemaString.isEmpty()) {
50+ schemaString.append(" \n " )
51+ }
52+ schemaString.append(string)
5053 }
5154
5255 /* *
@@ -134,21 +137,40 @@ class SchemaParserBuilder constructor(private val dictionary: SchemaParserDictio
134137 * Scan for classes with the supplied schema and dictionary. Used for testing.
135138 */
136139 private fun scan (): ScannedSchemaObjects {
137- val document = try {
138- Parser ().parseDocument(this .schemaString.toString())
140+ val definitions = parseDefinitions()
141+ val customScalars = scalars.associateBy { it.name }
142+
143+ return SchemaClassScanner (dictionary.getDictionary(), definitions, resolvers, customScalars, options)
144+ .scanForClasses()
145+ }
146+
147+ private fun parseDefinitions () = parseDocuments().flatMap { it.definitions }
148+
149+ private fun parseDocuments (): List <Document > {
150+ val parser = Parser ()
151+ val documents = mutableListOf<Document >()
152+ try {
153+ files.forEach { documents.add(parser.parseDocument(readFile(it), it)) }
154+
155+ if (! schemaString.isEmpty()) {
156+ documents.add(parser.parseDocument(this .schemaString.toString()))
157+ }
139158 } catch (pce: ParseCancellationException ) {
140159 val cause = pce.cause
141- if (cause != null && cause is RecognitionException ) {
160+ if (cause != null && cause is RecognitionException ) {
142161 throw InvalidSchemaError (pce, cause)
143162 } else {
144163 throw pce
145164 }
146165 }
166+ return documents
167+ }
147168
148- val definitions = document.definitions
149- val customScalars = scalars.associateBy { it.name }
150-
151- return SchemaClassScanner (dictionary.getDictionary(), definitions, resolvers, customScalars, options).scanForClasses()
169+ private fun readFile (filename : String ): String {
170+ return java.io.BufferedReader (java.io.InputStreamReader (
171+ object : Any () {}.javaClass.classLoader.getResourceAsStream(filename)
172+ ? : throw java.io.FileNotFoundException (" classpath:$filename " )
173+ )).readText()
152174 }
153175
154176 /* *
@@ -157,7 +179,7 @@ class SchemaParserBuilder constructor(private val dictionary: SchemaParserDictio
157179 fun build () = SchemaParser (scan())
158180}
159181
160- class InvalidSchemaError (pce : ParseCancellationException , private val recognitionException : RecognitionException ): RuntimeException(pce) {
182+ class InvalidSchemaError (pce : ParseCancellationException , private val recognitionException : RecognitionException ) : RuntimeException(pce) {
161183 override val message: String?
162184 get() = " Invalid schema provided (${recognitionException.javaClass.name} ) at: ${recognitionException.offendingToken} "
163185}
@@ -227,8 +249,11 @@ class SchemaParserDictionary {
227249
228250data class SchemaParserOptions internal constructor(val contextClass : Class <* >? , val genericWrappers : List <GenericWrapper >, val allowUnimplementedResolvers : Boolean , val objectMapperProvider : PerFieldObjectMapperProvider , val proxyHandlers : List <ProxyHandler >, val preferGraphQLResolver : Boolean ) {
229251 companion object {
230- @JvmStatic fun newOptions () = Builder ()
231- @JvmStatic fun defaultOptions () = Builder ().build()
252+ @JvmStatic
253+ fun newOptions () = Builder ()
254+
255+ @JvmStatic
256+ fun defaultOptions () = Builder ().build()
232257 }
233258
234259 class Builder {
@@ -247,7 +272,7 @@ data class SchemaParserOptions internal constructor(val contextClass: Class<*>?,
247272 fun contextClass (contextClass : KClass <* >) = this .apply {
248273 this .contextClass = contextClass.java
249274 }
250-
275+
251276 fun genericWrappers (genericWrappers : List <GenericWrapper >) = this .apply {
252277 this .genericWrappers.addAll(genericWrappers)
253278 }
@@ -271,6 +296,7 @@ data class SchemaParserOptions internal constructor(val contextClass: Class<*>?,
271296 fun objectMapperConfigurer (objectMapperConfigurer : ObjectMapperConfigurer ) = this .apply {
272297 this .objectMapperProvider = PerFieldConfiguringObjectMapperProvider (objectMapperConfigurer)
273298 }
299+
274300 fun objectMapperProvider (objectMapperProvider : PerFieldObjectMapperProvider ) = this .apply {
275301 this .objectMapperProvider = objectMapperProvider
276302 }
@@ -284,12 +310,12 @@ data class SchemaParserOptions internal constructor(val contextClass: Class<*>?,
284310 }
285311
286312 fun build (): SchemaParserOptions {
287- val wrappers = if (useDefaultGenericWrappers) {
313+ val wrappers = if (useDefaultGenericWrappers) {
288314 genericWrappers + listOf (
289- GenericWrapper (Future ::class , 0 ),
290- GenericWrapper (CompletableFuture ::class , 0 ),
291- GenericWrapper (CompletionStage ::class , 0 ),
292- GenericWrapper (Publisher ::class , 0 )
315+ GenericWrapper (Future ::class , 0 ),
316+ GenericWrapper (CompletableFuture ::class , 0 ),
317+ GenericWrapper (CompletionStage ::class , 0 ),
318+ GenericWrapper (Publisher ::class , 0 )
293319 )
294320 } else {
295321 genericWrappers
@@ -300,75 +326,78 @@ data class SchemaParserOptions internal constructor(val contextClass: Class<*>?,
300326 }
301327
302328 data class GenericWrapper (
303- val type : Class <* >,
304- val index : Int ,
305- val transformer : (Any , DataFetchingEnvironment ) -> Any? = { x, _ -> x },
306- val schemaWrapper : (JavaType ) -> JavaType = { x -> x }
329+ val type : Class <* >,
330+ val index : Int ,
331+ val transformer : (Any , DataFetchingEnvironment ) -> Any? = { x, _ -> x },
332+ val schemaWrapper : (JavaType ) -> JavaType = { x -> x }
307333 ) {
308334
309- constructor (type: Class <* >, index: Int ): this (type, index, { x, _ -> x })
310- constructor (type: KClass <* >, index: Int ): this (type.java, index, { x, _ -> x })
335+ constructor (type: Class <* >, index: Int ) : this (type, index, { x, _ -> x })
336+ constructor (type: KClass <* >, index: Int ) : this (type.java, index, { x, _ -> x })
311337
312338 companion object {
313339
314340 @Suppress(" UNCHECKED_CAST" )
315- @JvmStatic fun <T > withTransformer (
316- type : Class <T >,
317- index : Int ,
318- transformer : (T , DataFetchingEnvironment ) -> Any? ,
319- schemaWrapper : (JavaType ) -> JavaType = { x -> x }
320- ): GenericWrapper where T : Any {
341+ @JvmStatic
342+ fun <T > withTransformer (
343+ type : Class <T >,
344+ index : Int ,
345+ transformer : (T , DataFetchingEnvironment ) -> Any? ,
346+ schemaWrapper : (JavaType ) -> JavaType = { x -> x }
347+ ): GenericWrapper where T : Any {
321348 return GenericWrapper (type, index, transformer as (Any , DataFetchingEnvironment ) -> Any? , schemaWrapper)
322349 }
323-
350+
324351 fun <T > withTransformer (
325- type : KClass <T >,
326- index : Int ,
327- transformer : (T , DataFetchingEnvironment ) -> Any? ,
328- schemaWrapper : (JavaType ) -> JavaType = { x -> x }
329- ): GenericWrapper where T : Any {
352+ type : KClass <T >,
353+ index : Int ,
354+ transformer : (T , DataFetchingEnvironment ) -> Any? ,
355+ schemaWrapper : (JavaType ) -> JavaType = { x -> x }
356+ ): GenericWrapper where T : Any {
330357 return withTransformer(type.java, index, transformer, schemaWrapper)
331358 }
332359
333- @JvmStatic fun <T > withTransformer (
334- type : Class <T >,
335- index : Int ,
336- transformer : (T ) -> Any? ,
337- schemaWrapper : (JavaType ) -> JavaType = { x -> x }
338- ): GenericWrapper where T : Any {
360+ @JvmStatic
361+ fun <T > withTransformer (
362+ type : Class <T >,
363+ index : Int ,
364+ transformer : (T ) -> Any? ,
365+ schemaWrapper : (JavaType ) -> JavaType = { x -> x }
366+ ): GenericWrapper where T : Any {
339367 return withTransformer(type, index, { x, _ -> transformer.invoke(x) }, schemaWrapper)
340368 }
341369
342370 fun <T > withTransformer (
343- type : KClass <T >,
344- index : Int ,
345- transformer : (T ) -> Any? ,
346- schemaWrapper : (JavaType ) -> JavaType = { x -> x }
347- ): GenericWrapper where T : Any {
371+ type : KClass <T >,
372+ index : Int ,
373+ transformer : (T ) -> Any? ,
374+ schemaWrapper : (JavaType ) -> JavaType = { x -> x }
375+ ): GenericWrapper where T : Any {
348376 return withTransformer(type.java, index, transformer, schemaWrapper)
349377 }
350378
351- @JvmStatic fun <T > listCollectionWithTransformer (
352- type : Class <T >,
353- index : Int ,
354- transformer : (T ) -> Any?
355- ): GenericWrapper where T : Any {
379+ @JvmStatic
380+ fun <T > listCollectionWithTransformer (
381+ type : Class <T >,
382+ index : Int ,
383+ transformer : (T ) -> Any?
384+ ): GenericWrapper where T : Any {
356385 return withTransformer(
357- type,
358- index,
359- transformer,
360- { innerType -> ParameterizedTypeImpl .make(List ::class .java, arrayOf(innerType), null ) }
386+ type,
387+ index,
388+ transformer,
389+ { innerType -> ParameterizedTypeImpl .make(List ::class .java, arrayOf(innerType), null ) }
361390 )
362391 }
363392
364393 fun <T > listCollectionWithTransformer (
365- type : KClass <T >,
366- index : Int ,
367- transformer : (T ) -> Any?
368- ): GenericWrapper where T : Any {
394+ type : KClass <T >,
395+ index : Int ,
396+ transformer : (T ) -> Any?
397+ ): GenericWrapper where T : Any {
369398 return listCollectionWithTransformer(type.java, index, transformer)
370399 }
371400 }
372-
401+
373402 }
374403}
0 commit comments