Repository: graphql-java-kickstart/graphql-java-tools
Pull request #379 (2020-03-20 09:16:53)

Bugs/367 list ids as input not resolved correctly


Patch:
diff --git a/src/main/kotlin/graphql/kickstart/tools/MethodFieldResolver.kt b/src/main/kotlin/graphql/kickstart/tools/MethodFieldResolver.kt
index 959eff0..79cdb3f 100644
--- a/src/main/kotlin/graphql/kickstart/tools/MethodFieldResolver.kt
+++ b/src/main/kotlin/graphql/kickstart/tools/MethodFieldResolver.kt
@@ -11,6 +11,8 @@ import graphql.schema.DataFetchingEnvironment
 import graphql.schema.GraphQLTypeUtil.isScalar
 import kotlinx.coroutines.future.future
 import java.lang.reflect.Method
+import java.lang.reflect.ParameterizedType
+import java.lang.reflect.WildcardType
 import java.util.*
 import kotlin.coroutines.intrinsics.suspendCoroutineUninterceptedOrReturn
 import kotlin.reflect.full.valueParameters
@@ -22,216 +24,223 @@ import kotlin.reflect.jvm.kotlinFunction
  */
 internal class MethodFieldResolver(field: FieldDefinition, search: FieldResolverScanner.Search, options: SchemaParserOptions, val method: Method) : FieldResolver(field, search, options, search.type) {
 
-    companion object {
-        fun isBatched(method: Method, search: FieldResolverScanner.Search): Boolean {
-            if (method.getAnnotation(Batched::class.java) != null) {
-                if (!search.allowBatched) {
-                    throw ResolverError("The @Batched annotation is only allowed on non-root resolver methods, but it was found on ${search.type.unwrap().name}#${method.name}!")
-                }
-
-                return true
-            }
-            return false
+  companion object {
+    fun isBatched(method: Method, search: FieldResolverScanner.Search): Boolean {
+      if (method.getAnnotation(Batched::class.java) != null) {
+        if (!search.allowBatched) {
+          throw ResolverError("The @Batched annotation is only allowed on non-root resolver methods, but it was found on ${search.type.unwrap().name}#${method.name}!")
         }
-    }
 
-    private val additionalLastArgument =
-            try {
-                method.kotlinFunction?.valueParameters?.size ?: method.parameterCount == (field.inputValueDefinitions.size + getIndexOffset() + 1)
-            } catch (e: InternalError) {
-                method.parameterCount == (field.inputValueDefinitions.size + getIndexOffset() + 1)
-            }
-
-    override fun createDataFetcher(): DataFetcher<*> {
-        val batched = isBatched(method, search)
-        val args = mutableListOf<ArgumentPlaceholder>()
-        val mapper = options.objectMapperProvider.provide(field)
-
-        // Add source argument if this is a resolver (but not a root resolver)
-        if (this.search.requiredFirstParameterType != null) {
-            val expectedType = if (batched) Iterable::class.java else this.search.requiredFirstParameterType
-
-            args.add { environment ->
-                val source = environment.getSource<Any>()
-                if (!(expectedType.isAssignableFrom(source.javaClass))) {
-                    throw ResolverError("Source type (${source.javaClass.name}) is not expected type (${expectedType.name})!")
-                }
-
-                source
-            }
+        return true
+      }
+      return false
+    }
+  }
+
+  private val additionalLastArgument =
+      try {
+        method.kotlinFunction?.valueParameters?.size ?: method.parameterCount == (field.inputValueDefinitions.size + getIndexOffset() + 1)
+      } catch (e: InternalError) {
+        method.parameterCount == (field.inputValueDefinitions.size + getIndexOffset() + 1)
+      }
+
+  override fun createDataFetcher(): DataFetcher<*> {
+    val batched = isBatched(method, search)
+    val args = mutableListOf<ArgumentPlaceholder>()
+    val mapper = options.objectMapperProvider.provide(field)
+
+    // Add source argument if this is a resolver (but not a root resolver)
+    if (this.search.requiredFirstParameterType != null) {
+      val expectedType = if (batched) Iterable::class.java else this.search.requiredFirstParameterType
+
+      args.add { environment ->
+        val source = environment.getSource<Any>()
+        if (!(expectedType.isAssignableFrom(source.javaClass))) {
+          throw ResolverError("Source type (${source.javaClass.name}) is not expected type (${expectedType.name})!")
         }
 
-        // Add an argument for each argument defined in the GraphQL schema
-        this.field.inputValueDefinitions.forEachIndexed { index, definition ->
-
-            val genericParameterType = this.getJavaMethodParameterType(index)
-                    ?: throw ResolverError("Missing method type at position ${this.getJavaMethodParameterIndex(index)}, this is most likely a bug with graphql-java-tools")
-
-            val isNonNull = definition.type is NonNullType
-            val isOptional = this.genericType.getRawClass(genericParameterType) == Optional::class.java
-
-            val typeReference = object : TypeReference<Any>() {
-                override fun getType() = genericParameterType
-            }
-
-            args.add { environment ->
-                val value = environment.arguments[definition.name] ?: if (isNonNull) {
-                    throw ResolverError("Missing required argument with name '${definition.name}', this is most likely a bug with graphql-java-tools")
-                } else {
-                    null
-                }
-
-                if (value == null && isOptional) {
-                    if (environment.containsArgument(definition.name)) {
-                        return@add Optional.empty<Any>()
-                    } else {
-                        return@add null
-                    }
-                }
-
-                if (value != null
-                        && genericParameterType.unwrap().isAssignableFrom(value.javaClass)
-                        && isScalarType(environment, definition.type, genericParameterType)) {
-                    return@add value
-                }
-
-                return@add mapper.convertValue(value, typeReference)
-            }
-        }
+        source
+      }
+    }
 
-        // Add DataFetchingEnvironment/Context argument
-        if (this.additionalLastArgument) {
-            when (this.method.parameterTypes.last()) {
-                null -> throw ResolverError("Expected at least one argument but got none, this is most likely a bug with graphql-java-tools")
-                options.contextClass -> args.add { environment -> environment.getContext() }
-                else -> args.add { environment -> environment }
-            }
-        }
+    // Add an argument for each argument defined in the GraphQL schema
+    this.field.inputValueDefinitions.forEachIndexed { index, definition ->
 
-        return if (batched) {
-            BatchedMethodFieldResolverDataFetcher(getSourceResolver(), this.method, args, options)
-        } else {
-            if (args.isEmpty() && isTrivialDataFetcher(this.method)) {
-                TrivialMethodFieldResolverDataFetcher(getSourceResolver(), this.method, args, options)
-            } else {
-                MethodFieldResolverDataFetcher(getSourceResolver(), this.method, args, options)
-            }
+      val genericParameterType = this.getJavaMethodParameterType(index)
+          ?: throw ResolverError("Missing method type at position ${this.getJavaMethodParameterIndex(index)}, this is most likely a bug with graphql-java-tools")
 
-        }
-    }
+      val isNonNull = definition.type is NonNullType
+      val isOptional = this.genericType.getRawClass(genericParameterType) == Optional::class.java
 
-    private fun isScalarType(environment: DataFetchingEnvironment, type: Type<*>, genericParameterType: JavaType): Boolean =
-            when (type) {
-                is ListType -> List::class.java.isAssignableFrom(this.genericType.getRawClass(genericParameterType))
-                        && isScalarType(environment, type.type, this.genericType.unwrapGenericType(genericParameterType))
-                is TypeName -> environment.graphQLSchema?.getType(type.name)?.let { isScalar(it) } ?: false
-                is NonNullType -> isScalarType(environment, type.type, genericParameterType)
-                else -> false
-            }
-
-    override fun scanForMatches(): List<TypeClassMatcher.PotentialMatch> {
-        val batched = isBatched(method, search)
-        val unwrappedGenericType = genericType.unwrapGenericType(try {
-            method.kotlinFunction?.returnType?.javaType ?: method.genericReturnType
-        } catch (e: InternalError) {
-            method.genericReturnType
-        })
-        val returnValueMatch = TypeClassMatcher.PotentialMatch.returnValue(field.type, unwrappedGenericType, genericType, SchemaClassScanner.ReturnValueReference(method), batched)
-
-        return field.inputValueDefinitions.mapIndexed { i, inputDefinition ->
-            TypeClassMatcher.PotentialMatch.parameterType(inputDefinition.type, getJavaMethodParameterType(i)!!, genericType, SchemaClassScanner.MethodParameterReference(method, i), batched)
-        } + listOf(returnValueMatch)
-    }
+      val typeReference = object : TypeReference<Any>() {
+        override fun getType() = genericParameterType
+      }
 
-    private fun getIndexOffset(): Int {
-        return if (resolverInfo is DataClassTypeResolverInfo && !method.declaringClass.isAssignableFrom(resolverInfo.dataClassType)) {
-            1
+      args.add { environment ->
+        val value = environment.arguments[definition.name] ?: if (isNonNull) {
+          throw ResolverError("Missing required argument with name '${definition.name}', this is most likely a bug with graphql-java-tools")
         } else {
-            0
+          null
         }
-    }
-
-    private fun getJavaMethodParameterIndex(index: Int) = index + getIndexOffset()
 
-    private fun getJavaMethodParameterType(index: Int): JavaType? {
-        val methodIndex = getJavaMethodParameterIndex(index)
-        val parameters = method.parameterTypes
+        if (value == null && isOptional) {
+          if (environment.containsArgument(definition.name)) {
+            return@add Optional.empty<Any>()
+          } else {
+            return@add null
+          }
+        }
 
-        return if (parameters.size > methodIndex) {
-            method.genericParameterTypes[getJavaMethodParameterIndex(index)]
-        } else {
-            null
+        if (value != null
+            && genericParameterType.unwrap().isAssignableFrom(value.javaClass)
+            && isScalarType(environment, definition.type, genericParameterType)) {
+          return@add value
         }
+
+        return@add mapper.convertValue(value, typeReference)
+      }
     }
 
-    override fun toString() = "MethodFieldResolver{method=$method}"
-}
+    // Add DataFetchingEnvironment/Context argument
+    if (this.additionalLastArgument) {
+      when (this.method.parameterTypes.last()) {
+        null -> throw ResolverError("Expected at least one argument but got none, this is most likely a bug with graphql-java-tools")
+        options.contextClass -> args.add { environment -> environment.getContext() }
+        else -> args.add { environment -> environment }
+      }
+    }
 
-open class MethodFieldResolverDataFetcher(private val sourceResolver: SourceResolver, method: Method, private val args: List<ArgumentPlaceholder>, private val options: SchemaParserOptions) : DataFetcher<Any> {
+    return if (batched) {
+      BatchedMethodFieldResolverDataFetcher(getSourceResolver(), this.method, args, options)
+    } else {
+      if (args.isEmpty() && isTrivialDataFetcher(this.method)) {
+        TrivialMethodFieldResolverDataFetcher(getSourceResolver(), this.method, args, options)
+      } else {
+        MethodFieldResolverDataFetcher(getSourceResolver(), this.method, args, options)
+      }
 
-    // Convert to reflactasm reflection
-    private val methodAccess = MethodAccess.get(method.declaringClass)!!
-    private val methodIndex = methodAccess.getIndex(method.name, *method.parameterTypes)
-    private val isSuspendFunction = try {
-        method.kotlinFunction?.isSuspend == true
+    }
+  }
+
+  private fun isScalarType(environment: DataFetchingEnvironment, type: Type<*>, genericParameterType: JavaType): Boolean =
+      when (type) {
+        is ListType -> List::class.java.isAssignableFrom(this.genericType.getRawClass(genericParameterType))
+            && isScalarType(environment, type.type, this.genericType.unwrapGenericType(genericParameterType))
+        is TypeName -> environment.graphQLSchema?.getType(type.name)?.let { isScalar(it) && !isJavaLanguageType(genericParameterType) } ?: false
+        is NonNullType -> isScalarType(environment, type.type, genericParameterType)
+        else -> false
+      }
+
+  private fun isJavaLanguageType(type: JavaType): Boolean =
+      when (type) {
+        is ParameterizedType -> isJavaLanguageType(type.actualTypeArguments[0])
+        is WildcardType -> isJavaLanguageType(type.upperBounds[0])
+        else -> genericType.getRawClass(type).`package`.name == "java.lang"
+      }
+
+  override fun scanForMatches(): List<TypeClassMatcher.PotentialMatch> {
+    val batched = isBatched(method, search)
+    val unwrappedGenericType = genericType.unwrapGenericType(try {
+      method.kotlinFunction?.returnType?.javaType ?: method.genericReturnType
     } catch (e: InternalError) {
-        false
+      method.genericReturnType
+    })
+    val returnValueMatch = TypeClassMatcher.PotentialMatch.returnValue(field.type, unwrappedGenericType, genericType, SchemaClassScanner.ReturnValueReference(method), batched)
+
+    return field.inputValueDefinitions.mapIndexed { i, inputDefinition ->
+      TypeClassMatcher.PotentialMatch.parameterType(inputDefinition.type, getJavaMethodParameterType(i)!!, genericType, SchemaClassScanner.MethodParameterReference(method, i), batched)
+    } + listOf(returnValueMatch)
+  }
+
+  private fun getIndexOffset(): Int {
+    return if (resolverInfo is DataClassTypeResolverInfo && !method.declaringClass.isAssignableFrom(resolverInfo.dataClassType)) {
+      1
+    } else {
+      0
     }
+  }
 
-    private class CompareGenericWrappers {
-        companion object : Comparator<GenericWrapper> {
-            override fun compare(w1: GenericWrapper, w2: GenericWrapper): Int = when {
-                w1.type.isAssignableFrom(w2.type) -> 1
-                else -> -1
-            }
-        }
-    }
+  private fun getJavaMethodParameterIndex(index: Int) = index + getIndexOffset()
 
-    override fun get(environment: DataFetchingEnvironment): Any? {
-        val source = sourceResolver(environment)
-        val args = this.args.map { it(environment) }.toTypedArray()
+  private fun getJavaMethodParameterType(index: Int): JavaType? {
+    val methodIndex = getJavaMethodParameterIndex(index)
+    val parameters = method.parameterTypes
 
-        return if (isSuspendFunction) {
-            environment.coroutineScope().future(options.coroutineContextProvider.provide()) {
-                methodAccess.invokeSuspend(source, methodIndex, args)?.transformWithGenericWrapper(environment)
-            }
-        } else {
-            methodAccess.invoke(source, methodIndex, *args)?.transformWithGenericWrapper(environment)
-        }
+    return if (parameters.size > methodIndex) {
+      method.genericParameterTypes[getJavaMethodParameterIndex(index)]
+    } else {
+      null
     }
+  }
 
-    private fun Any.transformWithGenericWrapper(environment: DataFetchingEnvironment): Any? {
-        return options.genericWrappers
-                .asSequence()
-                .filter { it.type.isInstance(this) }
-                .sortedWith(CompareGenericWrappers)
-                .firstOrNull()
-                ?.transformer?.invoke(this, environment) ?: this
-    }
+  override fun toString() = "MethodFieldResolver{method=$method}"
+}
 
-    /**
-     * Function that return the object used to fetch the data
-     * It can be a DataFetcher or an entity
-     */
-    @Suppress("unused")
-    open fun getWrappedFetchingObject(environment: DataFetchingEnvironment): Any {
-        return sourceResolver(environment)
+open class MethodFieldResolverDataFetcher(private val sourceResolver: SourceResolver, method: Method, private val args: List<ArgumentPlaceholder>, private val options: SchemaParserOptions) : DataFetcher<Any> {
+
+  // Convert to reflactasm reflection
+  private val methodAccess = MethodAccess.get(method.declaringClass)!!
+  private val methodIndex = methodAccess.getIndex(method.name, *method.parameterTypes)
+  private val isSuspendFunction = try {
+    method.kotlinFunction?.isSuspend == true
+  } catch (e: InternalError) {
+    false
+  }
+
+  private class CompareGenericWrappers {
+    companion object : Comparator<GenericWrapper> {
+      override fun compare(w1: GenericWrapper, w2: GenericWrapper): Int = when {
+        w1.type.isAssignableFrom(w2.type) -> 1
+        else -> -1
+      }
+    }
+  }
+
+  override fun get(environment: DataFetchingEnvironment): Any? {
+    val source = sourceResolver(environment)
+    val args = this.args.map { it(environment) }.toTypedArray()
+
+    return if (isSuspendFunction) {
+      environment.coroutineScope().future(options.coroutineContextProvider.provide()) {
+        methodAccess.invokeSuspend(source, methodIndex, args)?.transformWithGenericWrapper(environment)
+      }
+    } else {
+      methodAccess.invoke(source, methodIndex, *args)?.transformWithGenericWrapper(environment)
     }
+  }
+
+  private fun Any.transformWithGenericWrapper(environment: DataFetchingEnvironment): Any? {
+    return options.genericWrappers
+        .asSequence()
+        .filter { it.type.isInstance(this) }
+        .sortedWith(CompareGenericWrappers)
+        .firstOrNull()
+        ?.transformer?.invoke(this, environment) ?: this
+  }
+
+  /**
+   * Function that return the object used to fetch the data
+   * It can be a DataFetcher or an entity
+   */
+  @Suppress("unused")
+  open fun getWrappedFetchingObject(environment: DataFetchingEnvironment): Any {
+    return sourceResolver(environment)
+  }
 }
 
-open class TrivialMethodFieldResolverDataFetcher(private val sourceResolver: SourceResolver, method: Method, private val args: List<ArgumentPlaceholder>, private val options: SchemaParserOptions) : MethodFieldResolverDataFetcher(sourceResolver, method, args, options), TrivialDataFetcher<Any> {
+open class TrivialMethodFieldResolverDataFetcher(sourceResolver: SourceResolver, method: Method, args: List<ArgumentPlaceholder>, options: SchemaParserOptions) : MethodFieldResolverDataFetcher(sourceResolver, method, args, options), TrivialDataFetcher<Any> {
 
 }
 
 private suspend inline fun MethodAccess.invokeSuspend(target: Any, methodIndex: Int, args: Array<Any?>): Any? {
-    return suspendCoroutineUninterceptedOrReturn { continuation ->
-        invoke(target, methodIndex, *args + continuation)
-    }
+  return suspendCoroutineUninterceptedOrReturn { continuation ->
+    invoke(target, methodIndex, *args + continuation)
+  }
 }
 
 class BatchedMethodFieldResolverDataFetcher(sourceResolver: SourceResolver, method: Method, args: List<ArgumentPlaceholder>, options: SchemaParserOptions) : MethodFieldResolverDataFetcher(sourceResolver, method, args, options) {
-    @Batched
-    override fun get(environment: DataFetchingEnvironment) = super.get(environment)
+  @Batched
+  override fun get(environment: DataFetchingEnvironment) = super.get(environment)
 }
 
 internal typealias ArgumentPlaceholder = (DataFetchingEnvironment) -> Any?


Test patch:
diff --git a/src/test/groovy/graphql/kickstart/tools/BuiltInLongIdSpec.groovy b/src/test/groovy/graphql/kickstart/tools/BuiltInLongIdSpec.groovy
new file mode 100644
index 0000000..1382467
--- /dev/null
+++ b/src/test/groovy/graphql/kickstart/tools/BuiltInLongIdSpec.groovy
@@ -0,0 +1,81 @@
+package graphql.kickstart.tools
+
+import graphql.GraphQL
+import graphql.execution.AsyncExecutionStrategy
+import graphql.schema.GraphQLSchema
+import spock.lang.Shared
+import spock.lang.Specification
+
+class BuiltInLongIdSpec extends Specification {
+
+    @Shared
+    GraphQL gql
+
+    def setupSpec() {
+        GraphQLSchema schema = SchemaParser.newParser().schemaString('''\
+                        type Query {
+                            itemByLongId(id: ID!): Item!
+                            itemsByLongIds(ids: [ID!]!): [Item!]!
+                        }
+                        
+                        type Item {
+                          id: ID!
+                        }
+                    '''.stripIndent())
+                .resolvers(new QueryWithLongItemResolver())
+                .build()
+                .makeExecutableSchema()
+        gql = GraphQL.newGraphQL(schema)
+                .queryExecutionStrategy(new AsyncExecutionStrategy())
+                .build()
+    }
+
+    def "supports Long as ID as input"() {
+        when:
+        def data = Utils.assertNoGraphQlErrors(gql) {
+            '''
+                {
+                    itemByLongId(id: 1) {
+                        id
+                    }
+                }
+                '''
+        }
+
+        then:
+        data.itemByLongId != null
+        data.itemByLongId.id == "1"
+    }
+
+    def "supports list of Long as ID as input"() {
+        when:
+        def data = Utils.assertNoGraphQlErrors(gql) {
+            '''
+                {
+                    itemsByLongIds(ids: [1,2,3]) {
+                        id
+                    }
+                }
+                '''
+        }
+
+        then:
+        data.itemsByLongIds != null
+        data.itemsByLongIds.size == 3
+        data.itemsByLongIds[0].id == "1"
+    }
+
+    class QueryWithLongItemResolver implements GraphQLQueryResolver {
+        Item itemByLongId(Long id) {
+            new Item(id: id)
+        }
+
+        List<Item> itemsByLongIds(List<Long> ids) {
+            ids.collect { new Item(id: it) }
+        }
+    }
+
+    class Item {
+        Long id
+    }
+}
diff --git a/src/test/groovy/graphql/kickstart/tools/EndToEndSpec.groovy b/src/test/groovy/graphql/kickstart/tools/EndToEndSpec.groovy
index e33d178..f77555a 100644
--- a/src/test/groovy/graphql/kickstart/tools/EndToEndSpec.groovy
+++ b/src/test/groovy/graphql/kickstart/tools/EndToEndSpec.groovy
@@ -29,23 +29,23 @@ class EndToEndSpec extends Specification {
         GraphQLSchema schema = EndToEndSpecHelperKt.createSchema()
 
         batchedGql = GraphQL.newGraphQL(schema)
-            .queryExecutionStrategy(new BatchedExecutionStrategy())
-            .build()
+                .queryExecutionStrategy(new BatchedExecutionStrategy())
+                .build()
 
         gql = GraphQL.newGraphQL(schema)
-            .queryExecutionStrategy(new AsyncExecutionStrategy())
-            .build()
+                .queryExecutionStrategy(new AsyncExecutionStrategy())
+                .build()
     }
 
     def "schema comments are used as descriptions"() {
         expect:
-            gql.graphQLSchema.allTypesAsList.find { it.name == 'Type' }?.valueDefinitionMap?.TYPE_1?.description == "Item type 1"
+        gql.graphQLSchema.allTypesAsList.find { it.name == 'Type' }?.valueDefinitionMap?.TYPE_1?.description == "Item type 1"
     }
 
     def "generated schema should respond to simple queries"() {
         when:
-            def data = Utils.assertNoGraphQlErrors(gql) {
-                '''
+        def data = Utils.assertNoGraphQlErrors(gql) {
+            '''
                 {
                     items(itemsInput: {name: "item1"}) {
                         id
@@ -53,16 +53,16 @@ class EndToEndSpec extends Specification {
                     }
                 }
                 '''
-            }
+        }
 
         then:
-            noExceptionThrown()
+        noExceptionThrown()
     }
 
     def "generated schema should respond to simple mutations"() {
         when:
-            def data = Utils.assertNoGraphQlErrors(gql, [name: "new1", type: Type.TYPE_2.toString()]) {
-                '''
+        def data = Utils.assertNoGraphQlErrors(gql, [name: "new1", type: Type.TYPE_2.toString()]) {
+            '''
                 mutation addNewItem($name: String!, $type: Type!) {
                     addItem(newItem: {name: $name, type: $type}) {
                         id
@@ -71,56 +71,56 @@ class EndToEndSpec extends Specification {
                     }
                 }
                 '''
-            }
+        }
 
         then:
-            data.addItem
+        data.addItem
     }
 
     def "generated schema should execute the subscription query"() {
         when:
-            def newItem = new Item(1, "item", Type.TYPE_1, UUID.randomUUID(), [])
-            def returnedItem = null
-            def data = Utils.assertNoGraphQlErrors(gql, [:], new OnItemCreatedContext(newItem)) {
-                '''
+        def newItem = new Item(1, "item", Type.TYPE_1, UUID.randomUUID(), [])
+        def returnedItem = null
+        def data = Utils.assertNoGraphQlErrors(gql, [:], new OnItemCreatedContext(newItem)) {
+            '''
                 subscription {
                     onItemCreated {
                         id
                     }
                 } 
                 '''
-            }
-            CountDownLatch latch = new CountDownLatch(1)
-            (data as Publisher<ExecutionResult>).subscribe(new Subscriber<ExecutionResult>() {
-                @Override
-                void onSubscribe(org.reactivestreams.Subscription s) {
+        }
+        CountDownLatch latch = new CountDownLatch(1)
+        (data as Publisher<ExecutionResult>).subscribe(new Subscriber<ExecutionResult>() {
+            @Override
+            void onSubscribe(org.reactivestreams.Subscription s) {
 
-                }
+            }
 
-                @Override
-                void onNext(ExecutionResult executionResult) {
-                    returnedItem = executionResult.data
-                    latch.countDown()
-                }
+            @Override
+            void onNext(ExecutionResult executionResult) {
+                returnedItem = executionResult.data
+                latch.countDown()
+            }
 
-                @Override
-                void onError(Throwable t) {
-                }
+            @Override
+            void onError(Throwable t) {
+            }
 
-                @Override
-                void onComplete() {
-                }
-            })
-            latch.await(3, TimeUnit.SECONDS)
+            @Override
+            void onComplete() {
+            }
+        })
+        latch.await(3, TimeUnit.SECONDS)
 
         then:
-            returnedItem.get("onItemCreated").id == 1
+        returnedItem.get("onItemCreated").id == 1
     }
 
     def "generated schema should handle interface types"() {
         when:
-            def data = Utils.assertNoGraphQlErrors(gql) {
-                '''
+        def data = Utils.assertNoGraphQlErrors(gql) {
+            '''
                 {
                     itemsByInterface {
                         name
@@ -128,16 +128,16 @@ class EndToEndSpec extends Specification {
                     }
                 }
                 '''
-            }
+        }
 
         then:
-            data.itemsByInterface
+        data.itemsByInterface
     }
 
     def "generated schema should handle union types"() {
         when:
-            def data = Utils.assertNoGraphQlErrors(gql) {
-                '''
+        def data = Utils.assertNoGraphQlErrors(gql) {
+            '''
                 {
                     allItems {
                         ... on Item {
@@ -151,16 +151,16 @@ class EndToEndSpec extends Specification {
                     }
                 }
                 '''
-            }
+        }
 
         then:
-            data.allItems
+        data.allItems
     }
 
     def "generated schema should handle nested union types"() {
         when:
-            def data = Utils.assertNoGraphQlErrors(gql) {
-                '''
+        def data = Utils.assertNoGraphQlErrors(gql) {
+            '''
                     {
                         nestedUnionItems {
                             ... on Item {
@@ -175,33 +175,33 @@ class EndToEndSpec extends Specification {
                         }
                     }
                     '''
-            }
+        }
 
         then:
-            data.nestedUnionItems == [[itemId: 0], [itemId: 1], [otherItemId: 0], [otherItemId: 1], [thirdItemId: 100]]
+        data.nestedUnionItems == [[itemId: 0], [itemId: 1], [otherItemId: 0], [otherItemId: 1], [thirdItemId: 100]]
     }
 
     def "generated schema should handle scalar types"() {
         when:
-            def data = Utils.assertNoGraphQlErrors(gql) {
-                '''
+        def data = Utils.assertNoGraphQlErrors(gql) {
+            '''
                 {
                     itemByUUID(uuid: "38f685f1-b460-4a54-a17f-7fd69e8cf3f8") {
                         uuid
                     }
                 }
                 '''
-            }
+        }
 
         then:
-            data.itemByUUID
+        data.itemByUUID
     }
 
     def "generated schema should handle non nullable scalar types"() {
         when:
         def fileParts = [new MockPart("test.doc", "Hello"), new MockPart("test.doc", "World")]
         def args = ["fileParts": fileParts]
-        def data = Utils.assertNoGraphQlErrors( gql,  args) {
+        def data = Utils.assertNoGraphQlErrors(gql, args) {
             '''
               mutation ($fileParts: [Upload!]!) { echoFiles(fileParts: $fileParts)}
             '''
@@ -224,7 +224,7 @@ class EndToEndSpec extends Specification {
         }
 
         then:
-            data.propertyHashMapItems == [ [name: "bob", age:55] ]
+        data.propertyHashMapItems == [[name: "bob", age: 55]]
     }
 
     def "generated schema should handle any java.util.Map (using SortedMap) types as property maps"() {
@@ -241,7 +241,7 @@ class EndToEndSpec extends Specification {
         }
 
         then:
-        data.propertySortedMapItems == [ [name: "Arthur", age:76], [name: "Jane", age:28] ]
+        data.propertySortedMapItems == [[name: "Arthur", age: 76], [name: "Jane", age: 28]]
     }
 
     // In this test a dictionary entry for the schema type ComplexMapItem is defined
@@ -251,7 +251,7 @@ class EndToEndSpec extends Specification {
     // resolver/POJO graph.
     def "generated schema should handle java.util.Map types as property maps when containing complex data"() {
         when:
-            def data = Utils.assertNoGraphQlErrors(gql) {
+        def data = Utils.assertNoGraphQlErrors(gql) {
             '''
                 {
                     propertyMapWithComplexItems {
@@ -265,7 +265,7 @@ class EndToEndSpec extends Specification {
         }
 
         then:
-            data.propertyMapWithComplexItems == [ [nameId:[id:150], age:72] ]
+        data.propertyMapWithComplexItems == [[nameId: [id: 150], age: 72]]
     }
 
     // This behavior is consistent with PropertyDataFetcher
@@ -283,7 +283,7 @@ class EndToEndSpec extends Specification {
         }
 
         then:
-        data.propertyMapMissingNamePropItems == [ [name: null, age:55] ]
+        data.propertyMapMissingNamePropItems == [[name: null, age: 55]]
     }
 
     // In this test a dictonary entry for the schema type NestedComplexMapItem is defined
@@ -308,14 +308,14 @@ class EndToEndSpec extends Specification {
         }
 
         then:
-        data.propertyMapWithNestedComplexItems == [ [ nested:[ item: [id:63] ], age:72] ]
+        data.propertyMapWithNestedComplexItems == [[nested: [item: [id: 63]], age: 72]]
     }
 
 
     def "generated schema should handle optional arguments"() {
         when:
-            def data = Utils.assertNoGraphQlErrors(gql) {
-                '''
+        def data = Utils.assertNoGraphQlErrors(gql) {
+            '''
                 {
                     missing: itemsWithOptionalInput {
                         id
@@ -326,17 +326,17 @@ class EndToEndSpec extends Specification {
                     }
                 }
                 '''
-            }
+        }
 
         then:
-            data.missing?.size > 1
-            data.present?.size == 1
+        data.missing?.size > 1
+        data.present?.size == 1
     }
 
     def "generated schema should handle optional arguments using java.util.Optional"() {
         when:
-            def data = Utils.assertNoGraphQlErrors(gql) {
-                '''
+        def data = Utils.assertNoGraphQlErrors(gql) {
+            '''
                 {
                     missing: itemsWithOptionalInputExplicit {
                         id
@@ -347,17 +347,17 @@ class EndToEndSpec extends Specification {
                     }
                 }
                 '''
-            }
+        }
 
         then:
-            data.missing?.size > 1
-            data.present?.size == 1
+        data.missing?.size > 1
+        data.present?.size == 1
     }
 
     def "generated schema should handle optional return types using java.util.Optional"() {
         when:
-            def data = Utils.assertNoGraphQlErrors(gql) {
-                '''
+        def data = Utils.assertNoGraphQlErrors(gql) {
+            '''
                 {
                     missing: optionalItem(itemsInput: {name: "item?"}) {
                         id
@@ -368,31 +368,31 @@ class EndToEndSpec extends Specification {
                     }
                 }
                 '''
-            }
+        }
 
         then:
-            data.missing == null
-            data.present
+        data.missing == null
+        data.present
     }
 
     def "generated schema should pass default arguments"() {
         when:
-            def data = Utils.assertNoGraphQlErrors(gql) {
-                '''
+        def data = Utils.assertNoGraphQlErrors(gql) {
+            '''
                 {
                     defaultArgument
                 }
                 '''
-            }
+        }
 
         then:
-            data.defaultArgument == true
+        data.defaultArgument == true
     }
 
     def "introspection shouldn't fail for arguments of type list with a default value (defaultEnumListArgument)"() {
         when:
-            def data = Utils.assertNoGraphQlErrors(gql) {
-                '''
+        def data = Utils.assertNoGraphQlErrors(gql) {
+            '''
                 {
                    __type(name: "Query") {
                        name
@@ -406,16 +406,16 @@ class EndToEndSpec extends Specification {
                    }
                 }
                 '''
-            }
+        }
 
         then:
-            data.__type
+        data.__type
     }
 
     def "generated schema should return null without errors for null value with nested fields"() {
         when:
-            def data = Utils.assertNoGraphQlErrors(gql) {
-                '''
+        def data = Utils.assertNoGraphQlErrors(gql) {
+            '''
                 {
                     complexNullableType {
                         first
@@ -424,31 +424,31 @@ class EndToEndSpec extends Specification {
                     }
                 }
                 '''
-            }
+        }
 
         then:
-            data.containsKey('complexNullableType')
-            data.complexNullableType == null
+        data.containsKey('complexNullableType')
+        data.complexNullableType == null
     }
 
     def "generated schema handles nested lists in input type fields"() {
         when:
-            def data = Utils.assertNoGraphQlErrors(gql) {
-                '''
+        def data = Utils.assertNoGraphQlErrors(gql) {
+            '''
                 {
                     complexInputType(complexInput: [[{first: "foo", second: [[{first: "bar"}]]}]])
                 }
                 '''
-            }
+        }
 
         then:
-            data.complexInputType
+        data.complexInputType
     }
 
     def "generated schema should use type extensions"() {
         when:
-            def data = Utils.assertNoGraphQlErrors(gql) {
-                '''
+        def data = Utils.assertNoGraphQlErrors(gql) {
+            '''
                 {
                     extendedType {
                         first
@@ -456,62 +456,62 @@ class EndToEndSpec extends Specification {
                     }
                 }
                 '''
-            }
+        }
 
         then:
-            data.extendedType
-            data.extendedType.first
-            data.extendedType.second
+        data.extendedType
+        data.extendedType.first
+        data.extendedType.second
     }
 
     def "generated schema uses properties if no methods are found"() {
         when:
-            def data = Utils.assertNoGraphQlErrors(gql) {
-                '''
+        def data = Utils.assertNoGraphQlErrors(gql) {
+            '''
                 {
                     propertyField
                 }
                 '''
-            }
+        }
 
         then:
-            data.propertyField
+        data.propertyField
     }
 
     def "generated schema allows enums in input types"() {
         when:
-            def data = Utils.assertNoGraphQlErrors(gql) {
-                '''
+        def data = Utils.assertNoGraphQlErrors(gql) {
+            '''
                 {
                     enumInputType(type: TYPE_2)
                 }
                 '''
-            }
+        }
 
         then:
-            data.enumInputType == "TYPE_2"
+        data.enumInputType == "TYPE_2"
     }
 
     def "generated schema works with custom scalars as input values"() {
         when:
-            def data = Utils.assertNoGraphQlErrors(gql) {
-                '''
+        def data = Utils.assertNoGraphQlErrors(gql) {
+            '''
                 {
                     customScalarMapInputType(customScalarMap: { test: "me" })
                 }
                 '''
-            }
+        }
 
         then:
-            data.customScalarMapInputType == [
+        data.customScalarMapInputType == [
                 test: "me"
-            ]
+        ]
     }
 
     def "generated schema supports generic properties"() {
         when:
         def data = Utils.assertNoGraphQlErrors(gql) {
-                '''
+            '''
                 {
                     itemWithGenericProperties {
                         keys
@@ -528,24 +528,24 @@ class EndToEndSpec extends Specification {
 
     def "generated schema supports batched datafetchers"() {
         when:
-            def data = Utils.assertNoGraphQlErrors(batchedGql) {
-                '''
+        def data = Utils.assertNoGraphQlErrors(batchedGql) {
+            '''
                 {
                     allBaseItems {
                         name: batchedName
                     }
                 }
                 '''
-            }
+        }
 
         then:
-            data.allBaseItems.collect { it.name } == ['item1', 'item2']
+        data.allBaseItems.collect { it.name } == ['item1', 'item2']
     }
 
     def "generated schema supports batched datafetchers with params"() {
         when:
-            def data = Utils.assertNoGraphQlErrors(batchedGql) {
-                '''
+        def data = Utils.assertNoGraphQlErrors(batchedGql) {
+            '''
                 {
                     allBaseItems {
                         tags: batchedWithParamsTags(names: ["item2-tag1"]) {
@@ -554,49 +554,49 @@ class EndToEndSpec extends Specification {
                     }
                 }
                 '''
-            }
+        }
 
         then:
-            data.allBaseItems.collect { it.tags.collect { it.name } } == [[], ['item2-tag1']]
+        data.allBaseItems.collect { it.tags.collect { it.name } } == [[], ['item2-tag1']]
     }
 
     def "generated schema supports overriding built-in scalars"() {
         when:
-            def data = Utils.assertNoGraphQlErrors(gql) {
-                '''
+        def data = Utils.assertNoGraphQlErrors(gql) {
+            '''
                 {
                     itemByBuiltInId(id: "38f685f1-b460-4a54-a17f-7fd69e8cf3f8") {
                         name
                     }
                 }
                 '''
-            }
+        }
 
         then:
-            noExceptionThrown()
-            data.itemByBuiltInId != null
+        noExceptionThrown()
+        data.itemByBuiltInId != null
     }
 
     def "generated schema supports DataFetcherResult"() {
         when:
-            def data = Utils.assertNoGraphQlErrors(gql) {
-                '''
+        def data = Utils.assertNoGraphQlErrors(gql) {
+            '''
                 {
                     dataFetcherResult {
                         name
                     }
                 }
                 '''
-            }
+        }
 
         then:
-            data.dataFetcherResult.name == "item1"
+        data.dataFetcherResult.name == "item1"
     }
 
     def "generated schema supports Kotlin suspend functions"() {
         when:
-            def data = Utils.assertNoGraphQlErrors(gql) {
-                '''
+        def data = Utils.assertNoGraphQlErrors(gql) {
+            '''
                     {
                         coroutineItems {
                             id
@@ -604,63 +604,64 @@ class EndToEndSpec extends Specification {
                         }
                     }
                     '''
-            }
+        }
 
         then:
-            data.coroutineItems == [[id:0, name:"item1"], [id:1, name:"item2"]]
+        data.coroutineItems == [[id: 0, name: "item1"], [id: 1, name: "item2"]]
     }
 
     def "generated schema supports Kotlin coroutine channels for the subscription query"() {
         when:
-            def newItem = new Item(1, "item", Type.TYPE_1, UUID.randomUUID(), [])
-            def data = Utils.assertNoGraphQlErrors(gql, [:], new OnItemCreatedContext(newItem)) {
-                '''
+        def newItem = new Item(1, "item", Type.TYPE_1, UUID.randomUUID(), [])
+        def data = Utils.assertNoGraphQlErrors(gql, [:], new OnItemCreatedContext(newItem)) {
+            '''
                     subscription {
                         onItemCreatedCoroutineChannel {
                             id
                         }
                     } 
                     '''
-            }
-            def subscriber = new TestEnvironment().newManualSubscriber(data as Publisher<ExecutionResult>)
+        }
+        def subscriber = new TestEnvironment().newManualSubscriber(data as Publisher<ExecutionResult>)
 
         then:
-            subscriber.requestNextElement().data.get("onItemCreatedCoroutineChannel").id == 1
-            subscriber.expectCompletion()
+        subscriber.requestNextElement().data.get("onItemCreatedCoroutineChannel").id == 1
+        subscriber.expectCompletion()
     }
 
     def "generated schema supports Kotlin coroutine channels with suspend function for the subscription query"() {
         when:
-            def newItem = new Item(1, "item", Type.TYPE_1, UUID.randomUUID(), [])
-            def data = Utils.assertNoGraphQlErrors(gql, [:], new OnItemCreatedContext(newItem)) {
-                '''
+        def newItem = new Item(1, "item", Type.TYPE_1, UUID.randomUUID(), [])
+        def data = Utils.assertNoGraphQlErrors(gql, [:], new OnItemCreatedContext(newItem)) {
+            '''
                         subscription {
                             onItemCreatedCoroutineChannelAndSuspendFunction {
                                 id
                             }
                         } 
                         '''
-            }
-            def subscriber = new TestEnvironment().newManualSubscriber(data as Publisher<ExecutionResult>)
+        }
+        def subscriber = new TestEnvironment().newManualSubscriber(data as Publisher<ExecutionResult>)
 
         then:
-            subscriber.requestNextElement().data.get("onItemCreatedCoroutineChannelAndSuspendFunction").id == 1
-            subscriber.expectCompletion()
+        subscriber.requestNextElement().data.get("onItemCreatedCoroutineChannelAndSuspendFunction").id == 1
+        subscriber.expectCompletion()
     }
 
     def "generated schema supports arrays"() {
         when:
-            def data = Utils.assertNoGraphQlErrors(gql) {
-                '''
+        def data = Utils.assertNoGraphQlErrors(gql) {
+            '''
                 {
                     arrayItems {
                         name
                     }
                 }
                 '''
-            }
+        }
 
         then:
-            data.arrayItems.collect { it.name } == ['item1', 'item2']
+        data.arrayItems.collect { it.name } == ['item1', 'item2']
     }
+
 }
diff --git a/src/test/kotlin/graphql/kickstart/tools/EndToEndSpecHelper.kt b/src/test/kotlin/graphql/kickstart/tools/EndToEndSpecHelper.kt
index 38480e0..22e2f50 100644
--- a/src/test/kotlin/graphql/kickstart/tools/EndToEndSpecHelper.kt
+++ b/src/test/kotlin/graphql/kickstart/tools/EndToEndSpecHelper.kt
@@ -16,17 +16,17 @@ import java.util.concurrent.CompletableFuture
 import javax.servlet.http.Part
 
 fun createSchema() = SchemaParser.newParser()
-        .schemaString(schemaDefinition)
-        .resolvers(Query(), Mutation(), Subscription(), ItemResolver(), UnusedRootResolver(), UnusedResolver(), EchoFilesResolver())
-        .scalars(customScalarUUID, customScalarMap, customScalarId, uploadScalar)
-        .dictionary("OtherItem", OtherItemWithWrongName::class)
-        .dictionary("ThirdItem", ThirdItem::class)
-        .dictionary("ComplexMapItem", ComplexMapItem::class)
-        .dictionary("NestedComplexMapItem", NestedComplexMapItem::class)
-        .build()
-        .makeExecutableSchema()
-
-val schemaDefinition = """
+    .schemaString(schemaDefinition)
+    .resolvers(Query(), Mutation(), Subscription(), ItemResolver(), UnusedRootResolver(), UnusedResolver(), EchoFilesResolver())
+    .scalars(customScalarUUID, customScalarMap, customScalarId, uploadScalar)
+    .dictionary("OtherItem", OtherItemWithWrongName::class)
+    .dictionary("ThirdItem", ThirdItem::class)
+    .dictionary("ComplexMapItem", ComplexMapItem::class)
+    .dictionary("NestedComplexMapItem", NestedComplexMapItem::class)
+    .build()
+    .makeExecutableSchema()
+
+private const val schemaDefinition = """
 
 ## Private comment!
 scalar UUID
@@ -212,157 +212,157 @@ type ItemWithGenericProperties {
 
 
 val items = mutableListOf(
-        Item(0, "item1", Type.TYPE_1, UUID.fromString("38f685f1-b460-4a54-a17f-7fd69e8cf3f8"), listOf(Tag(1, "item1-tag1"), Tag(2, "item1-tag2"))),
-        Item(1, "item2", Type.TYPE_2, UUID.fromString("38f685f1-b460-4a54-b17f-7fd69e8cf3f8"), listOf(Tag(3, "item2-tag1"), Tag(4, "item2-tag2")))
+    Item(0, "item1", Type.TYPE_1, UUID.fromString("38f685f1-b460-4a54-a17f-7fd69e8cf3f8"), listOf(Tag(1, "item1-tag1"), Tag(2, "item1-tag2"))),
+    Item(1, "item2", Type.TYPE_2, UUID.fromString("38f685f1-b460-4a54-b17f-7fd69e8cf3f8"), listOf(Tag(3, "item2-tag1"), Tag(4, "item2-tag2")))
 )
 
 val otherItems = mutableListOf(
-        OtherItemWithWrongName(0, "otherItem1", Type.TYPE_1, UUID.fromString("38f685f1-b460-4a54-c17f-7fd69e8cf3f8")),
-        OtherItemWithWrongName(1, "otherItem2", Type.TYPE_2, UUID.fromString("38f685f1-b460-4a54-d17f-7fd69e8cf3f8"))
+    OtherItemWithWrongName(0, "otherItem1", Type.TYPE_1, UUID.fromString("38f685f1-b460-4a54-c17f-7fd69e8cf3f8")),
+    OtherItemWithWrongName(1, "otherItem2", Type.TYPE_2, UUID.fromString("38f685f1-b460-4a54-d17f-7fd69e8cf3f8"))
 )
 
 val thirdItems = mutableListOf(
-        ThirdItem(100)
+    ThirdItem(100)
 )
 
 val propetyHashMapItems = mutableListOf(
-        hashMapOf("name" to "bob", "age" to 55)
+    hashMapOf("name" to "bob", "age" to 55)
 )
 
 val propertyMapMissingNamePropItems = mutableListOf(
-        hashMapOf<String, Any>("age" to 55)
+    hashMapOf<String, Any>("age" to 55)
 )
 
 val propetySortedMapItems = mutableListOf(
-        sortedMapOf("name" to "Arthur", "age" to 76),
-        sortedMapOf("name" to "Jane", "age" to 28)
+    sortedMapOf("name" to "Arthur", "age" to 76),
+    sortedMapOf("name" to "Jane", "age" to 28)
 )
 
 val propertyMapWithComplexItems = mutableListOf(
-        hashMapOf("nameId" to ComplexMapItem(150), "age" to 72)
+    hashMapOf("nameId" to ComplexMapItem(150), "age" to 72)
 )
 
 val propertyMapWithNestedComplexItems = mutableListOf(
-        hashMapOf("nested" to NestedComplexMapItem(UndiscoveredItem(63)), "age" to 72)
+    hashMapOf("nested" to NestedComplexMapItem(UndiscoveredItem(63)), "age" to 72)
 )
 
 class Query : GraphQLQueryResolver, ListListResolver<String>() {
-    fun isEmpty() = items.isEmpty()
-    fun allBaseItems() = items
-    fun items(input: ItemSearchInput): List<Item> = items.filter { it.name == input.name }
-    fun optionalItem(input: ItemSearchInput) = items(input).firstOrNull()?.let { Optional.of(it) } ?: Optional.empty()
-    fun allItems(): List<Any> = items + otherItems
-    fun otherUnionItems(): List<Any> = items + thirdItems
-    fun nestedUnionItems(): List<Any> = items + otherItems + thirdItems
-    fun itemsByInterface(): List<ItemInterface> = items + otherItems
-    fun itemByUUID(uuid: UUID): Item? = items.find { it.uuid == uuid }
-    fun itemByBuiltInId(id: UUID): Item? {
-        return items.find { it.uuid == id }
-    }
+  fun isEmpty() = items.isEmpty()
+  fun allBaseItems() = items
+  fun items(input: ItemSearchInput): List<Item> = items.filter { it.name == input.name }
+  fun optionalItem(input: ItemSearchInput) = items(input).firstOrNull()?.let { Optional.of(it) } ?: Optional.empty()
+  fun allItems(): List<Any> = items + otherItems
+  fun otherUnionItems(): List<Any> = items + thirdItems
+  fun nestedUnionItems(): List<Any> = items + otherItems + thirdItems
+  fun itemsByInterface(): List<ItemInterface> = items + otherItems
+  fun itemByUUID(uuid: UUID): Item? = items.find { it.uuid == uuid }
+  fun itemByBuiltInId(id: UUID): Item? {
+    return items.find { it.uuid == id }
+  }
 
-    fun itemsWithOptionalInput(input: ItemSearchInput?) = if (input == null) items else items(input)
-    fun itemsWithOptionalInputExplicit(input: Optional<ItemSearchInput>?) = if (input?.isPresent == true) items(input.get()) else items
-    fun enumInputType(type: Type) = type
-    fun customScalarMapInputType(customScalarMap: Map<String, Any>) = customScalarMap
-    fun itemWithGenericProperties() = ItemWithGenericProperties(listOf("A", "B"))
+  fun itemsWithOptionalInput(input: ItemSearchInput?) = if (input == null) items else items(input)
+  fun itemsWithOptionalInputExplicit(input: Optional<ItemSearchInput>?) = if (input?.isPresent == true) items(input.get()) else items
+  fun enumInputType(type: Type) = type
+  fun customScalarMapInputType(customScalarMap: Map<String, Any>) = customScalarMap
+  fun itemWithGenericProperties() = ItemWithGenericProperties(listOf("A", "B"))
 
-    fun defaultArgument(arg: Boolean) = arg
-    fun defaultEnumListArgument(types: List<Type>) = types
+  fun defaultArgument(arg: Boolean) = arg
+  fun defaultEnumListArgument(types: List<Type>) = types
 
-    fun futureItems() = CompletableFuture.completedFuture(items)
-    fun complexNullableType(): ComplexNullable? = null
+  fun futureItems() = CompletableFuture.completedFuture(items)
+  fun complexNullableType(): ComplexNullable? = null
 
-    fun complexInputType(input: List<List<ComplexInputType>?>?) = input?.firstOrNull()?.firstOrNull()?.let { it.first == "foo" && it.second?.firstOrNull()?.firstOrNull()?.first == "bar" }
-            ?: false
+  fun complexInputType(input: List<List<ComplexInputType>?>?) = input?.firstOrNull()?.firstOrNull()?.let { it.first == "foo" && it.second?.firstOrNull()?.firstOrNull()?.first == "bar" }
+      ?: false
 
-    fun extendedType() = ExtendedType()
+  fun extendedType() = ExtendedType()
 
-    fun getItemsWithGetResolver() = items
+  fun getItemsWithGetResolver() = items
 
-    fun getFieldClass() = items
-    fun getFieldHashCode() = items
+  fun getFieldClass() = items
+  fun getFieldHashCode() = items
 
-    fun propertyHashMapItems() = propetyHashMapItems
-    fun propertyMapMissingNamePropItems() = propertyMapMissingNamePropItems
-    fun propertySortedMapItems() = propetySortedMapItems
-    fun propertyMapWithComplexItems() = propertyMapWithComplexItems
-    fun propertyMapWithNestedComplexItems() = propertyMapWithNestedComplexItems
+  fun propertyHashMapItems() = propetyHashMapItems
+  fun propertyMapMissingNamePropItems() = propertyMapMissingNamePropItems
+  fun propertySortedMapItems() = propetySortedMapItems
+  fun propertyMapWithComplexItems() = propertyMapWithComplexItems
+  fun propertyMapWithNestedComplexItems() = propertyMapWithNestedComplexItems
 
-    private val propertyField = "test"
+  private val propertyField = "test"
 
-    fun dataFetcherResult(): DataFetcherResult<Item> {
-        return DataFetcherResult.newResult<Item>().data(items.first()).build()
-    }
+  fun dataFetcherResult(): DataFetcherResult<Item> {
+    return DataFetcherResult.newResult<Item>().data(items.first()).build()
+  }
 
-    suspend fun coroutineItems(): List<Item> = CompletableDeferred(items).await()
+  suspend fun coroutineItems(): List<Item> = CompletableDeferred(items).await()
 
-    fun arrayItems() = items.toTypedArray()
+  fun arrayItems() = items.toTypedArray()
 }
 
 class UnusedRootResolver : GraphQLQueryResolver
 class UnusedResolver : GraphQLResolver<String>
 
 class ExtendedType {
-    fun first() = "test"
-    fun second() = "test"
+  fun first() = "test"
+  fun second() = "test"
 }
 
 abstract class ListListResolver<out E> {
-    fun listList(): List<List<E>> = listOf(listOf())
+  fun listList(): List<List<E>> = listOf(listOf())
 }
 
 class Mutation : GraphQLMutationResolver {
-    fun addItem(input: NewItemInput): Item {
-        return Item(items.size, input.name, input.type, UUID.randomUUID(), listOf()) // Don't actually add the item to the list, since we want the test to be deterministic
-    }
+  fun addItem(input: NewItemInput): Item {
+    return Item(items.size, input.name, input.type, UUID.randomUUID(), listOf()) // Don't actually add the item to the list, since we want the test to be deterministic
+  }
 }
 
 class OnItemCreatedContext(val newItem: Item)
 
 class Subscription : GraphQLSubscriptionResolver {
-    fun onItemCreated(env: DataFetchingEnvironment) =
-            Publisher<Item> { subscriber ->
-                subscriber.onNext(env.getContext<OnItemCreatedContext>().newItem)
+  fun onItemCreated(env: DataFetchingEnvironment) =
+      Publisher<Item> { subscriber ->
+        subscriber.onNext(env.getContext<OnItemCreatedContext>().newItem)
 //            subscriber.onComplete()
-            }
-
-    fun onItemCreatedCoroutineChannel(env: DataFetchingEnvironment): ReceiveChannel<Item> {
-        val channel = Channel<Item>(1)
-        channel.offer(env.getContext<OnItemCreatedContext>().newItem)
-        return channel
-    }
-
-    suspend fun onItemCreatedCoroutineChannelAndSuspendFunction(env: DataFetchingEnvironment): ReceiveChannel<Item> {
-        return coroutineScope {
-            val channel = Channel<Item>(1)
-            channel.offer(env.getContext<OnItemCreatedContext>().newItem)
-            channel
-        }
+      }
+
+  fun onItemCreatedCoroutineChannel(env: DataFetchingEnvironment): ReceiveChannel<Item> {
+    val channel = Channel<Item>(1)
+    channel.offer(env.getContext<OnItemCreatedContext>().newItem)
+    return channel
+  }
+
+  suspend fun onItemCreatedCoroutineChannelAndSuspendFunction(env: DataFetchingEnvironment): ReceiveChannel<Item> {
+    return coroutineScope {
+      val channel = Channel<Item>(1)
+      channel.offer(env.getContext<OnItemCreatedContext>().newItem)
+      channel
     }
+  }
 }
 
 class ItemResolver : GraphQLResolver<Item> {
-    fun tags(item: Item, names: List<String>?): List<Tag> = item.tags.filter { names?.contains(it.name) ?: true }
+  fun tags(item: Item, names: List<String>?): List<Tag> = item.tags.filter { names?.contains(it.name) ?: true }
 
-    @Batched
-    fun batchedName(items: List<Item>) = items.map { it.name }
+  @Batched
+  fun batchedName(items: List<Item>) = items.map { it.name }
 
-    @Batched
-    fun batchedWithParamsTags(items: List<Item>, names: List<String>?): List<List<Tag>> = items.map {
-        it.tags.filter {
-            names?.contains(it.name) ?: true
-        }
+  @Batched
+  fun batchedWithParamsTags(items: List<Item>, names: List<String>?): List<List<Tag>> = items.map {
+    it.tags.filter {
+      names?.contains(it.name) ?: true
     }
+  }
 }
 
-class EchoFilesResolver: GraphQLMutationResolver {
-    fun echoFiles(fileParts: List<Part>): List<String> = fileParts.map { String(it.inputStream.readBytes()) }
+class EchoFilesResolver : GraphQLMutationResolver {
+  fun echoFiles(fileParts: List<Part>): List<String> = fileParts.map { String(it.inputStream.readBytes()) }
 }
 
 interface ItemInterface {
-    val name: String
-    val type: Type
-    val uuid: UUID
+  val name: String
+  val type: Type
+  val uuid: UUID
 }
 
 enum class Type { TYPE_1, TYPE_2 }
@@ -379,99 +379,99 @@ data class ComplexNullable(val first: String, val second: String, val third: Str
 data class ComplexInputType(val first: String, val second: List<List<ComplexInputTypeTwo>?>?)
 data class ComplexInputTypeTwo(val first: String)
 data class ItemWithGenericProperties(val keys: List<String>)
-class MockPart(private val name: String, private val content: String):Part{
-    override fun getSubmittedFileName(): String  = name
-    override fun getName(): String = name
-    override fun write(fileName: String?) = throw IllegalArgumentException("Not supported")
-    override fun getHeader(name: String): String? = null
-    override fun getSize(): Long  = content.toByteArray().size.toLong()
-    override fun getContentType(): String? =null
-    override fun getHeaders(name: String?): Collection<String> = listOf()
-    override fun getHeaderNames(): Collection<String>  = listOf()
-    override fun getInputStream(): InputStream  = content.byteInputStream()
-    override fun delete()  = throw IllegalArgumentException("Not supported")
+class MockPart(private val name: String, private val content: String) : Part {
+  override fun getSubmittedFileName(): String = name
+  override fun getName(): String = name
+  override fun write(fileName: String?) = throw IllegalArgumentException("Not supported")
+  override fun getHeader(name: String): String? = null
+  override fun getSize(): Long = content.toByteArray().size.toLong()
+  override fun getContentType(): String? = null
+  override fun getHeaders(name: String?): Collection<String> = listOf()
+  override fun getHeaderNames(): Collection<String> = listOf()
+  override fun getInputStream(): InputStream = content.byteInputStream()
+  override fun delete() = throw IllegalArgumentException("Not supported")
 }
 
 val customScalarId = GraphQLScalarType.newScalar()
-        .name("ID")
-        .description("Overrides built-in ID")
-        .coercing(object : Coercing<UUID, String> {
-            override fun serialize(input: Any): String? = when (input) {
-                is String -> input
-                is UUID -> input.toString()
-                else -> null
-            }
-
-            override fun parseValue(input: Any): UUID? = parseLiteral(input)
-
-            override fun parseLiteral(input: Any): UUID? = when (input) {
-                is StringValue -> UUID.fromString(input.value)
-                else -> null
-            }
-        })
-        .build()
+    .name("ID")
+    .description("Overrides built-in ID")
+    .coercing(object : Coercing<UUID, String> {
+      override fun serialize(input: Any): String? = when (input) {
+        is String -> input
+        is UUID -> input.toString()
+        else -> null
+      }
+
+      override fun parseValue(input: Any): UUID? = parseLiteral(input)
+
+      override fun parseLiteral(input: Any): UUID? = when (input) {
+        is StringValue -> UUID.fromString(input.value)
+        else -> null
+      }
+    })
+    .build()
 
 val customScalarUUID = GraphQLScalarType.newScalar()
-        .name("UUID")
-        .description("UUID")
-        .coercing(object : Coercing<UUID, String> {
+    .name("UUID")
+    .description("UUID")
+    .coercing(object : Coercing<UUID, String> {
 
-            override fun serialize(input: Any): String? = when (input) {
-                is String -> input
-                is UUID -> input.toString()
-                else -> null
-            }
+      override fun serialize(input: Any): String? = when (input) {
+        is String -> input
+        is UUID -> input.toString()
+        else -> null
+      }
 
-            override fun parseValue(input: Any): UUID? = parseLiteral(input)
+      override fun parseValue(input: Any): UUID? = parseLiteral(input)
 
-            override fun parseLiteral(input: Any): UUID? = when (input) {
-                is StringValue -> UUID.fromString(input.value)
-                else -> null
-            }
-        })
-        .build()
+      override fun parseLiteral(input: Any): UUID? = when (input) {
+        is StringValue -> UUID.fromString(input.value)
+        else -> null
+      }
+    })
+    .build()
 
 val customScalarMap = GraphQLScalarType.newScalar()
-        .name("customScalarMap")
-        .description("customScalarMap")
-        .coercing(object : Coercing<Map<String, Any>, Map<String, Any>> {
+    .name("customScalarMap")
+    .description("customScalarMap")
+    .coercing(object : Coercing<Map<String, Any>, Map<String, Any>> {
 
-            @Suppress("UNCHECKED_CAST")
-            override fun parseValue(input: Any?): Map<String, Any> = input as Map<String, Any>
+      @Suppress("UNCHECKED_CAST")
+      override fun parseValue(input: Any?): Map<String, Any> = input as Map<String, Any>
 
-            @Suppress("UNCHECKED_CAST")
-            override fun serialize(dataFetcherResult: Any?): Map<String, Any> = dataFetcherResult as Map<String, Any>
+      @Suppress("UNCHECKED_CAST")
+      override fun serialize(dataFetcherResult: Any?): Map<String, Any> = dataFetcherResult as Map<String, Any>
 
-            override fun parseLiteral(input: Any?): Map<String, Any> = (input as ObjectValue).objectFields.associateBy { it.name }.mapValues { (it.value.value as StringValue).value }
-        })
-        .build()
+      override fun parseLiteral(input: Any?): Map<String, Any> = (input as ObjectValue).objectFields.associateBy { it.name }.mapValues { (it.value.value as StringValue).value }
+    })
+    .build()
 
 //Definition from https://github.com/graphql-java-kickstart/graphql-java-servlet/blob/master/src/main/java/graphql/servlet/core/ApolloScalars.java
 val uploadScalar: GraphQLScalarType = GraphQLScalarType.newScalar()
-        .name("Upload")
-        .description("A file part in a multipart request")
-        .coercing(object : Coercing<Part?, Void?> {
-            override fun serialize(dataFetcherResult: Any): Void? {
-                throw CoercingSerializeException("Upload is an input-only type")
-            }
-
-            override fun parseValue(input: Any?): Part? {
-                return when (input) {
-                    is Part -> {
-                        input
-                    }
-                    null -> {
-                        null
-                    }
-                    else -> {
-                        throw CoercingParseValueException("Expected type ${Part::class.java.name} but was ${input.javaClass.name}")
-                    }
-                }
-            }
-
-            override fun parseLiteral(input: Any): Part? {
-                throw CoercingParseLiteralException(
-                        "Must use variables to specify Upload values")
-            }
-        }).build()
+    .name("Upload")
+    .description("A file part in a multipart request")
+    .coercing(object : Coercing<Part?, Void?> {
+      override fun serialize(dataFetcherResult: Any): Void? {
+        throw CoercingSerializeException("Upload is an input-only type")
+      }
+
+      override fun parseValue(input: Any?): Part? {
+        return when (input) {
+          is Part -> {
+            input
+          }
+          null -> {
+            null
+          }
+          else -> {
+            throw CoercingParseValueException("Expected type ${Part::class.java.name} but was ${input.javaClass.name}")
+          }
+        }
+      }
+
+      override fun parseLiteral(input: Any): Part? {
+        throw CoercingParseLiteralException(
+            "Must use variables to specify Upload values")
+      }
+    }).build()